diff --git a/.github/workflows/branch-name-validator.yml b/.github/workflows/branch-name-validator.yml new file mode 100644 index 00000000000..d613cfe22d6 --- /dev/null +++ b/.github/workflows/branch-name-validator.yml @@ -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: (HCMPRE|HCMPOST|HCMSUB)-123-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" diff --git a/.github/workflows/buildWorkbenchUI.yml b/.github/workflows/buildWorkbenchUI.yml deleted file mode 100644 index 1a0c526d1bf..00000000000 --- a/.github/workflows/buildWorkbenchUI.yml +++ /dev/null @@ -1,64 +0,0 @@ -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/publishAllPackages.yml b/.github/workflows/publishAllPackages.yml deleted file mode 100644 index 6bb4b51d612..00000000000 --- a/.github/workflows/publishAllPackages.yml +++ /dev/null @@ -1,25 +0,0 @@ -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 deleted file mode 100644 index ff9b6a3a93f..00000000000 --- a/.github/workflows/publishAllPackagesRelease.yml +++ /dev/null @@ -1,20 +0,0 @@ -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 index 19fde98c7ab..33e224b222c 100644 --- a/.github/workflows/publishProjectFactory.yml +++ b/.github/workflows/publishProjectFactory.yml @@ -1,77 +1,72 @@ -name: project factory service docker Image CI +name: Project Factory Service Test Builder on: push: - branches: [ "campaign" ] + branches: + - "console" + - "master" paths: - - 'utilities/project-factory/**' + - 'health-services/project-factory/**' pull_request: - branches: [ "campaign" ] + branches: + - "console" + - "master" jobs: - build: - runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 # Fetch all history for tags and branches + # Step 1: Checkout the repository + - 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 + # Step 2: Set up environment variables + - name: Set up environment variables + id: env + run: | + echo "ACTION_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV - - 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" + # Step 3: Build the service Docker image + - name: Build the service Docker image + id: docker_build + working-directory: ./health-services/project-factory + run: | + IMAGE_TAG=egovio/project-factory:${{ env.ACTION_NUMBER }} + docker build . \ + --file Dockerfile \ + --tag $IMAGE_TAG + echo "::set-output name=image_name::$IMAGE_TAG" + echo "Service Docker image built successfully" + # Step 4: Build the database migration Docker image + - name: Build the DB migration Docker image + id: docker_db_build + working-directory: ./health-services/project-factory/migration + run: | + IMAGE_TAG=egovio/project-factory-db:${{ env.ACTION_NUMBER }} + docker build . \ + --file Dockerfile \ + --tag $IMAGE_TAG + echo "::set-output name=db_image_name::$IMAGE_TAG" + echo "DB migration Docker image built successfully" - - 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" + node_build: + runs-on: ubuntu-latest + + steps: + # Step 1: Checkout the repository + - uses: actions/checkout@v3 + # Step 2: Set up Node.js environment + - uses: actions/setup-node@v2 + with: + node-version: 20 - - 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" + # Step 3: Install dependencies and build for production + - name: Install dependencies and build + working-directory: ./health-services/project-factory + run: | + yarn install + yarn build 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/CODEOWNERS b/CODEOWNERS index cacb23525d2..7833b872775 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1,3 @@ -* @kavi-egov @sathishp-eGov @shashwat-egov +* @kavi-egov @sathishp-eGov + +health-services/project-factory/ @jagankumar-egov diff --git a/build/build-config.yml b/build/build-config.yml index dec24965782..2002805a366 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -250,15 +250,22 @@ 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: - 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 diff --git a/core-services/egov-hrms/pom.xml b/core-services/egov-hrms/pom.xml index 0a0507aa5a4..ff717d747cc 100644 --- a/core-services/egov-hrms/pom.xml +++ b/core-services/egov-hrms/pom.xml @@ -39,11 +39,11 @@ org.flywaydb flyway-core - 9.22.3 org.postgresql postgresql + 42.7.1 org.egov.services 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 1f0522f0d36..14e911985c0 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 @@ -82,7 +82,13 @@ public class PropertiesManager { @Value("${egov.idgen.path}") public String idGenEndpoint; - + + // Email + @Value("${kafka.topics.notification.email}") + private String emailNotifTopic; + + @Value("${notification.email.enabled}") + private Boolean isEmailNotificationEnabled; //Kafka Topics @Value("${kafka.topics.save.service}") @@ -96,7 +102,9 @@ public class PropertiesManager { @Value("${kafka.topics.hrms.updateData}") public String updateTopic; - + + @Value("${kafka.topics.hrms.email.notification}") + public String hrmsEmailNotifTopic; //Variables @Value("${egov.idgen.ack.name}") @@ -140,4 +148,10 @@ public class PropertiesManager { @Value("${egov.boundary.search.url}") private String boundarySearchUrl; + + @Value("${hrms.email.notification.implementation.partner}") + public String emailNotificationImplementationPartner; + + @Value("${hrms.email.notification.website.link}") + public String emailNotificationWebsiteLink; } \ 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 index a4c33b0c096..74b2360cd73 100644 --- 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 @@ -32,12 +32,17 @@ public class HrmsConsumer { @Autowired private PropertiesManager propertiesManager; - @KafkaListener(topics = {"${kafka.topics.hrms.updateData}"}) + @KafkaListener(topics = {"${kafka.topics.hrms.updateData}", "${kafka.topics.hrms.email.notification}"}) 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); + + if(topic.equals(propertiesManager.getHrmsEmailNotifTopic())) { + notificationService.processEmailNotification(employeeRequest); + } else { + 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/service/EmployeeService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java index 2cecd5f5f71..c42d487fa2d 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 @@ -121,8 +121,12 @@ public EmployeeResponse create(EmployeeRequest employeeRequest) { enrichCreateRequest(employee, requestInfo); createUser(employee, requestInfo); pwdMap.put(employee.getUuid(), employee.getUser().getPassword()); - employee.getUser().setPassword(null); }); + hrmsProducer.push(propertiesManager.getHrmsEmailNotifTopic(), employeeRequest); + + // Setting password as null after sending employeeRequest to email notification topic to send email. + employeeRequest.getEmployees().forEach(employee -> employee.getUser().setPassword(null)); + hrmsProducer.push(propertiesManager.getSaveEmployeeTopic(), employeeRequest); notificationService.sendNotification(employeeRequest, pwdMap); return generateResponse(employeeRequest); @@ -137,6 +141,7 @@ public EmployeeResponse create(EmployeeRequest employeeRequest) { */ public EmployeeResponse search(EmployeeSearchCriteria criteria, RequestInfo requestInfo) { boolean userChecked = false; + Long totalCount = 0L; /*if(null == criteria.getIsActive() || criteria.getIsActive()) criteria.setIsActive(true); else @@ -156,6 +161,7 @@ public EmployeeResponse search(EmployeeSearchCriteria criteria, RequestInfo requ userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_USERNAME, criteria.getCodes().get(0)); } UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + totalCount = userResponse.getTotalCount(); userChecked =true; if(!CollectionUtils.isEmpty(userResponse.getUser())) { mapOfUsers.putAll(userResponse.getUser().stream() @@ -178,6 +184,7 @@ public EmployeeResponse search(EmployeeSearchCriteria criteria, RequestInfo requ 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); + totalCount = userResponse.getTotalCount(); userChecked =true; if(!CollectionUtils.isEmpty(userResponse.getUser())) { mapOfUsers.putAll(userResponse.getUser().stream() @@ -191,6 +198,32 @@ public EmployeeResponse search(EmployeeSearchCriteria criteria, RequestInfo requ else criteria.setUuids(userUUIDs); } + + if(!CollectionUtils.isEmpty(criteria.getUserServiceUuids())) { + List userUUIDs = new ArrayList<>(); + 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_USER_SERVICE_UUIDS, criteria.getUserServiceUuids()); + if(!CollectionUtils.isEmpty(criteria.getNames())) + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_NAME, criteria.getNames().get(0)); + UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + totalCount = userResponse.getTotalCount(); + 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); @@ -207,6 +240,7 @@ public EmployeeResponse search(EmployeeSearchCriteria criteria, RequestInfo requ if(mapOfUsers.isEmpty()){ log.info("searching in user service"); UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + totalCount = userResponse.getTotalCount(); if(!CollectionUtils.isEmpty(userResponse.getUser())) { mapOfUsers = userResponse.getUser().stream() .collect(Collectors.toMap(User :: getUuid, Function.identity())); @@ -217,7 +251,8 @@ public EmployeeResponse search(EmployeeSearchCriteria criteria, RequestInfo requ } } return EmployeeResponse.builder().responseInfo(factory.createResponseInfoFromRequestInfo(requestInfo, true)) - .employees(employees).build(); + .employees(employees) + .totalCount(totalCount).build(); } 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 6a967bf8cfb..40482914921 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 @@ -22,7 +22,6 @@ 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.Name; @@ -33,10 +32,12 @@ 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.IndividualBulkResponse; 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.HRMS_USER_SEARCH_CRITERA_USER_SERVICE_UUIDS; import static org.egov.hrms.utils.HRMSConstants.SYSTEM_GENERATED; @Slf4j @@ -210,6 +211,7 @@ public UserResponse getUser(RequestInfo requestInfo, Map userSea mobileNumberList ) .id((List) userSearchCriteria.get("uuid")) + .userUuid((List) userSearchCriteria.get(HRMS_USER_SEARCH_CRITERA_USER_SERVICE_UUIDS)) .roleCodes((List) userSearchCriteria.get("roleCodes")) .username(usernameList) // given name @@ -331,6 +333,7 @@ private static UserResponse mapToUserResponse(IndividualBulkResponse response) { .responseInfo(response.getResponseInfo()) .user(response.getIndividual().stream() .map(IndividualService::getUser).collect(Collectors.toList())) + .totalCount(response.getTotalCount()) .build(); return userResponse; } 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 index acb427e4ce7..a8915e3983c 100644 --- 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 @@ -11,30 +11,40 @@ import org.egov.hrms.producer.HRMSProducer; import org.egov.hrms.repository.RestCallRepository; import org.egov.hrms.utils.HRMSConstants; +import org.egov.hrms.utils.NotificationUtil; +import org.egov.hrms.web.contract.EmailRequest; 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.util.CollectionUtils; import org.springframework.web.client.RestTemplate; +import static org.egov.hrms.utils.HRMSConstants.HEALTH_HRMS_EMAIL_LOCALIZATION_CODE; + @Service @Slf4j public class NotificationService { - - @Autowired + private HRMSProducer producer; - - @Autowired + private RestCallRepository repository; - @Autowired private RestTemplate restTemplate; + private NotificationUtil notificationUtil; + + public NotificationService(HRMSProducer producer, RestCallRepository repository, RestTemplate restTemplate, NotificationUtil notificationUtil) { + this.producer = producer; + this.repository = repository; + this.restTemplate = restTemplate; + this.notificationUtil = notificationUtil; + } + @Value("${kafka.topics.notification.sms}") private String smsTopic; @@ -193,4 +203,26 @@ public Map> getLocalisedMessages(RequestInfo request return localizedMessageMap; } + /** + * Creates and sends email notification to the employees whose details are provided in the employeeRequest. + * + * @param employeeRequest The employee request with employee details. + */ + public void processEmailNotification(EmployeeRequest employeeRequest) { + if (employeeRequest == null || CollectionUtils.isEmpty(employeeRequest.getEmployees())) { + log.error("Invalid employee request received for email notification"); + return; + } + try { + // Fetch localization messages and get email message template for HEALTH_HRMS_EMAIL_LOCALIZATION_CODE template code. + String localizationMessages = notificationUtil.getLocalizationMessages(employeeRequest); + String messageTemplate = notificationUtil.getMessageTemplate(HEALTH_HRMS_EMAIL_LOCALIZATION_CODE, localizationMessages); + + // Create email requests from the employee details provided in the employeeRequest. + List emailRequests = notificationUtil.createEmailRequest(employeeRequest, messageTemplate); + notificationUtil.sendEmail(emailRequests); + } catch (Exception e) { + log.error("Error processing email notification for given employees"); + } + } } 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 index 0d01b642d97..34ef1076fdb 100644 --- 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 @@ -30,6 +30,8 @@ public class HRMSConstants { 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 HEALTH_HRMS_LOCALIZATION_MODULE_CODE = "rainmaker-hr"; + public static final String HEALTH_HRMS_EMAIL_LOCALIZATION_CODE = "HEALTH_HRMS_EMAIL_CODE"; 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"; @@ -39,6 +41,7 @@ public class HRMSConstants { 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_USER_SERVICE_UUIDS = "userServiceUuids"; 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"; diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/NotificationUtil.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/NotificationUtil.java new file mode 100644 index 00000000000..22b8ea41493 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/NotificationUtil.java @@ -0,0 +1,154 @@ +package org.egov.hrms.utils; + +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.hrms.config.PropertiesManager; +import org.egov.hrms.model.Employee; +import org.egov.hrms.producer.HRMSProducer; +import org.egov.hrms.repository.RestCallRepository; +import org.egov.hrms.web.contract.Email; +import org.egov.hrms.web.contract.EmailRequest; +import org.egov.hrms.web.contract.EmployeeRequest; +import org.egov.hrms.web.contract.RequestInfoWrapper; +import org.json.JSONObject; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; + +import static org.egov.hrms.utils.HRMSConstants.*; + +@Slf4j +@Component +public class NotificationUtil { + + private RestCallRepository restCallRepository; + + private PropertiesManager propertiesManager; + + private HRMSProducer producer; + + public NotificationUtil(RestCallRepository restCallRepository, PropertiesManager propertiesManager, HRMSProducer producer) { + this.restCallRepository = restCallRepository; + this.propertiesManager = propertiesManager; + this.producer = producer; + } + + /** + * Extracts message for the specific code from the localization messages. + * + * @param notificationCode The code for which message is required. + * @param localizationMessage The localization messages. + * @return message for the specific code. + */ + public String getMessageTemplate(String notificationCode, String localizationMessage) { + // Create the path to get the message for the provided notification code from localization messages. + String path = "$..messages[?(@.code==\"{}\")].message"; + path = path.replace("{}", notificationCode); + String message = null; + try { + // Tries to get the message for the provided notificationCode. + List data = JsonPath.parse(localizationMessage).read(path); + if (!CollectionUtils.isEmpty(data)) + message = data.get(0).toString(); + else + log.error("Fetching from localization failed with code " + notificationCode); + } catch (Exception e) { + log.warn("Fetching from localization failed", e); + } + return message; + } + + /** + * Fetches all the localization messages from localization service. + * + * @param employeeRequest The employee request + * @return Localization messages for the module + */ + public String getLocalizationMessages(EmployeeRequest employeeRequest) { + + RequestInfoWrapper requestInfoWrapper = new RequestInfoWrapper(); + requestInfoWrapper.setRequestInfo(employeeRequest.getRequestInfo()); + + LinkedHashMap responseMap = (LinkedHashMap) restCallRepository.fetchResult(getUri(employeeRequest), requestInfoWrapper); + return new JSONObject(responseMap).toString(); + } + + /** + * Returns the search uri for the localization search to get localization messages from "rainmaker-hr" module. + * + * @param employeeRequest The employee request with locale code. + * @return The uri for localization search call. + */ + public StringBuilder getUri(EmployeeRequest employeeRequest) { + String tenantId = employeeRequest.getEmployees().get(0).getTenantId().split("\\.")[0]; + + String locale = HRMS_LOCALIZATION_ENG_LOCALE_CODE; + if (!StringUtils.isEmpty(employeeRequest.getRequestInfo().getMsgId()) && employeeRequest.getRequestInfo().getMsgId().split("|").length >= 2) + locale = employeeRequest.getRequestInfo().getMsgId().split("\\|")[1]; + + StringBuilder uri = new StringBuilder(); + uri.append(propertiesManager.getLocalizationHost()).append(propertiesManager.getLocalizationSearchEndpoint()) + .append("?").append("locale=").append(locale).append("&tenantId=").append(tenantId).append("&module=").append(HEALTH_HRMS_LOCALIZATION_MODULE_CODE); + + return uri; + } + + /** + * Replaces the placeholders from the email template and creates an email request from the given employee request. + * + * + * @param employeeRequest The employee request + * @param emailTemplate the email template + * @return The list of email requests + */ + public List createEmailRequest(EmployeeRequest employeeRequest, String emailTemplate) { + RequestInfo requestInfo = employeeRequest.getRequestInfo(); + + List emailRequest = new LinkedList<>(); + + // Iterate over each employee details and create email request for each employee. + for (Employee employee : employeeRequest.getEmployees()) { + String customizedMsg = emailTemplate.replace("{User's name}", employee.getUser().getName()); + customizedMsg = customizedMsg.replace("{Username}", employee.getCode()); + customizedMsg = customizedMsg.replace("{Password}", employee.getUser().getPassword()); + customizedMsg = customizedMsg.replace("{website URL}", propertiesManager.getEmailNotificationWebsiteLink()); + customizedMsg = customizedMsg.replace("{Implementation partner}", propertiesManager.getEmailNotificationImplementationPartner()); + + // Get email subject and email body from the provided email template. + String subject = customizedMsg.substring(customizedMsg.indexOf("

")+4, customizedMsg.indexOf("

")); + String body = customizedMsg.substring(customizedMsg.indexOf("")+5); + + // Create the email object with the employee's email id, subject and customized email body created. + Email emailObj = Email.builder().emailTo(Collections.singleton(employee.getUser().getEmailId())).isHTML(true).body(body).subject(subject).build(); + EmailRequest email = new EmailRequest(requestInfo, emailObj); + emailRequest.add(email); + } + return emailRequest; + } + + /** + * Pushes email request list into email notification topic if email notification is enabled. + * + * @param emailRequestList The list of emailRequests. + */ + public void sendEmail(List emailRequestList) { + if (propertiesManager.getIsEmailNotificationEnabled()) { + if (CollectionUtils.isEmpty(emailRequestList)) { + log.error("No Emails Found!"); + } else { + // Iterate over each email and push them into emailNotifTopic to send emails. + for (EmailRequest emailRequest : emailRequestList) { + producer.push(propertiesManager.getEmailNotifTopic(), emailRequest); + log.info("Email Request -> " + emailRequest.toString()); + log.info("EMAIL notification sent!"); + } + } + } + } +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/Email.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/Email.java new file mode 100644 index 00000000000..68c6011e4e4 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/Email.java @@ -0,0 +1,31 @@ +package org.egov.hrms.web.contract; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Set; + +@Setter +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Data +@Builder +public class Email { + + @NotNull + @Size(min = 1, message = "At least one recipient is required") + private Set emailTo; + + @NotBlank(message = "Subject is required") + private String subject; + + @NotBlank(message = "Body is required") + private String body; + @JsonProperty("isHTML") + private boolean isHTML; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmailRequest.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmailRequest.java new file mode 100644 index 00000000000..015b31217b1 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmailRequest.java @@ -0,0 +1,16 @@ +package org.egov.hrms.web.contract; + +import lombok.*; +import org.egov.common.contract.request.RequestInfo; + +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Setter +@Getter +@ToString +public class EmailRequest { + + private RequestInfo requestInfo; + private Email email; +} 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 index 6fb5141aeed..df8fb1538e5 100644 --- 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 @@ -54,6 +54,7 @@ import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; + @Builder @AllArgsConstructor @EqualsAndHashCode @@ -69,4 +70,8 @@ public class EmployeeResponse { @JsonProperty("Employees") private List employees; + @JsonProperty("TotalCount") + @Builder.Default + private Long totalCount = 0L; + } \ 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 index f5a3f9dfca6..052f98a7072 100644 --- 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 @@ -23,38 +23,40 @@ @Builder public class EmployeeSearchCriteria { - public List codes; + private List codes; - public List names; + private List names; - public List departments; + private List departments; - public List designations; + private List designations; - public Long asOnDate; + private Long asOnDate; - public List roles; + private List roles; - public List ids; + private List ids; - public List employeestatuses; + private List employeestatuses; - public List employeetypes; + private List employeetypes; - public List uuids; + private List uuids; + + private List userServiceUuids; - public List positions; + private List positions; - public Boolean isActive; + private Boolean isActive; @Size(max = 250) - public String tenantId; + private String tenantId; - public String phone; + private String phone; - public Integer offset; + private Integer offset; - public Integer limit; + private Integer limit; private Boolean includeUnassigned = false; 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 index 285964a0a87..ea727df4cbd 100644 --- 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 @@ -43,6 +43,7 @@ import java.util.ArrayList; import java.util.List; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Builder; import org.egov.common.contract.response.ResponseInfo; @@ -66,4 +67,8 @@ public class UserResponse { private List user = new ArrayList(); + @JsonIgnore + @Builder.Default + private Long totalCount = 0L; + } \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualBulkResponse.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualBulkResponse.java new file mode 100644 index 00000000000..845d6cb72d0 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualBulkResponse.java @@ -0,0 +1,54 @@ +package org.egov.hrms.web.models; + +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.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.individual.Individual; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +/** + * IndividualBulkResponse + */ +@Validated + + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class IndividualBulkResponse { + + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + + @JsonProperty("Individual") + @Valid + private List individual = null; + + public IndividualBulkResponse addIndividualItem(Individual individualItem) { + if (this.individual == null) { + this.individual = new ArrayList<>(); + } + this.individual.add(individualItem); + return this; + } + +} diff --git a/core-services/egov-hrms/src/main/resources/application.properties b/core-services/egov-hrms/src/main/resources/application.properties index dcece925352..6333f704295 100644 --- a/core-services/egov-hrms/src/main/resources/application.properties +++ b/core-services/egov-hrms/src/main/resources/application.properties @@ -65,6 +65,7 @@ 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 +egov.individual.delete.endpoint=/individual/v1/_delete # use qualifier as "defaultUserService" to integrate with egov-user module # use qualifier as "individualService" to integrate with individual module @@ -101,7 +102,9 @@ spring.kafka.producer.value-serializer=org.springframework.kafka.support.seriali kafka.topics.save.service=save-hrms-employee kafka.topics.update.service=update-hrms-employee kafka.topics.notification.sms=egov.core.notification.sms +kafka.topics.notification.email=egov.core.notification.email kafka.topics.hrms.updateData= egov-hrms-update +kafka.topics.hrms.email.notification=hrms-send-email-notification spring.kafka.listener.missing-topics-fatal=false @@ -117,6 +120,12 @@ state.level.tenant.id=default egov.hrms.auto.generate.password=true +# EMAIL NOTIFICATION CONFIG +notification.email.enabled=true + +hrms.email.notification.implementation.partner=NMCP Mozambique +hrms.email.notification.website.link=https://unified-qa.digit.org/microplan-ui + # BOUNDARY SERVICE egov.boundary.host=http://localhost:8081 egov.boundary.search.url=/boundary-service/boundary/_search 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..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 @@ -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 uuids user uuids + * @param employeeUuids employee uuids * @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..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,10 +159,12 @@ private void validateDepartment(ServiceRequest request, Object mdmsData){ String serviceCode = request.getService().getServiceCode(); List assignes = request.getWorkflow().getAssignes(); + List hrmsAssignes = request.getWorkflow().getHrmsAssignees(); + 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..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 @@ -35,6 +35,10 @@ public class Workflow { @Valid private List assignes = null; + @JsonProperty("hrmsAssignes") + @Valid + private List hrmsAssignees = null; + @SafeHtml @JsonProperty("comments") private String comments = null; 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 151055f4c03..f04bced991b 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/core-services/service-request/src/main/java/org/egov/servicerequest/error/ErrorCode.java b/core-services/service-request/src/main/java/org/egov/servicerequest/error/ErrorCode.java index c9e5f7b3cb0..e1a99338c3c 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/error/ErrorCode.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/error/ErrorCode.java @@ -31,6 +31,8 @@ public class ErrorCode { public static final String SERVICE_REQUEST_ATTRIBUTE_INVALID_MULTI_VALUE_LIST_VALUE_MSG = "Attribute Value provided against the attribute definition of type multi value list must be an instance of list"; + public static final String SERVICE_REQUEST_ATTRIBUTE_INVALID_BOOLEAN_VALUE_MSG = "Attribute Value provided against the attribute definition of type boolean must be an instance of boolean"; + public static final String INVALID_SIZE_OF_INPUT_CODE = "INVALID_SIZE_OF_INPUT_CODE"; public static final String INVALID_SIZE_OF_TEXT_MSG = "Text value cannot be of length greater than configured length "; diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java b/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java index 66595568bc1..67b2929b36d 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java @@ -21,25 +21,7 @@ import java.util.Map; import java.util.Set; -import static org.egov.servicerequest.error.ErrorCode.INVALID_SIZE_OF_INPUT_CODE; -import static org.egov.servicerequest.error.ErrorCode.INVALID_SIZE_OF_TEXT_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_DATETIME_VALUE_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_MULTI_VALUE_LIST_VALUE_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_NUMBER_VALUE_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_SINGLE_VALUE_LIST_VALUE_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_STRING_VALUE_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_TEXT_VALUE_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_CODE; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_MULTIVALUELIST_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_SINGLEVALUELIST_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_VALUES_UNIQUENESS_ERR_CODE; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_VALUES_UNIQUENESS_ERR_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_INVALID_SERVICE_DEF_ID_CODE; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_INVALID_SERVICE_DEF_ID_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_REQUIRED_ATTRIBUTE_NOT_PROVIDED_ERR_CODE; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_REQUIRED_ATTRIBUTE_NOT_PROVIDED_ERR_MSG; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_UNRECOGNIZED_ATTRIBUTE_CODE; -import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_UNRECOGNIZED_ATTRIBUTE_MSG; +import static org.egov.servicerequest.error.ErrorCode.*; @Slf4j @Component @@ -133,6 +115,10 @@ private void validateAttributeValuesAgainstServiceDefinition(ServiceDefinition s if(!(attributeValue.getValue() instanceof List)){ throw new CustomException(SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_CODE, SERVICE_REQUEST_ATTRIBUTE_INVALID_MULTI_VALUE_LIST_VALUE_MSG); } + }else if(attributeCodeVsDataType.get(attributeValue.getAttributeCode()).equals(AttributeDefinition.DataTypeEnum.BOOLEAN)){ + if(!(attributeValue.getValue() instanceof Boolean)){ + throw new CustomException(SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_CODE, SERVICE_REQUEST_ATTRIBUTE_INVALID_BOOLEAN_VALUE_MSG); + } } }); diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java index cefb96adac8..62616b6b677 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java @@ -41,7 +41,7 @@ public class AttributeDefinition { @JsonProperty("code") @NotNull - @Size(min = 2, max = 64) + @Size(min = 2, max = 256) private String code = null; /** @@ -50,6 +50,8 @@ public class AttributeDefinition { public enum DataTypeEnum { STRING("String"), + BOOLEAN("Boolean"), + NUMBER("Number"), TEXT("Text"), @@ -60,7 +62,9 @@ public enum DataTypeEnum { MULTIVALUELIST("MultiValueList"), - FILE("File"); + FILE("File"), + + BOOLEAN("Boolean"); private String value; @@ -110,7 +114,7 @@ public static DataTypeEnum fromValue(String text) { @Valid private AuditDetails auditDetails = null; - @JsonProperty("additionalDetails") + @JsonProperty("additionalFields") private Object additionalDetails = null; diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java index 8aeff4e39f3..98ce105e9b3 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java @@ -41,7 +41,7 @@ public class AttributeValue { @Valid private AuditDetails auditDetails = null; - @JsonProperty("additionalDetails") + @JsonProperty("additionalFields") private Object additionalDetails = null; diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/Service.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/Service.java index b0348458c15..4fc646ca8ea 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/Service.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/Service.java @@ -51,7 +51,7 @@ public class Service { @Valid private AuditDetails auditDetails = null; - @JsonProperty("additionalDetails") + @JsonProperty("additionalFields") private Object additionalDetails = null; @JsonProperty("accountId") diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinition.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinition.java index e91eeedf541..01b9b31fac9 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinition.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinition.java @@ -35,7 +35,7 @@ public class ServiceDefinition { @JsonProperty("code") @NotNull - @Size(min = 2, max = 64) + @Size(min = 2, max = 256) private String code = null; @JsonProperty("isActive") @@ -50,7 +50,7 @@ public class ServiceDefinition { @Valid private AuditDetails auditDetails = null; - @JsonProperty("additionalDetails") + @JsonProperty("additionalFields") private Object additionalDetails = null; @JsonProperty("clientId") diff --git a/core-services/service-request/src/main/resources/db/migration/main/V20241115143930__servicedefinition_alter_ddl.sql b/core-services/service-request/src/main/resources/db/migration/main/V20241115143930__servicedefinition_alter_ddl.sql new file mode 100644 index 00000000000..ed8ce4007ca --- /dev/null +++ b/core-services/service-request/src/main/resources/db/migration/main/V20241115143930__servicedefinition_alter_ddl.sql @@ -0,0 +1,9 @@ +-- Migration script to alter the length of 'code' column in both tables to 256 + +-- Update eg_service_definition table +ALTER TABLE eg_service_definition +ALTER COLUMN code TYPE character varying(256); + +-- Update eg_service_attribute_definition table +ALTER TABLE eg_service_attribute_definition +ALTER COLUMN code TYPE character varying(256); diff --git a/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/census-service/CHANGELOG.md b/health-services/census-service/CHANGELOG.md new file mode 100644 index 00000000000..38562489c90 --- /dev/null +++ b/health-services/census-service/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog +All notable changes to this module will be documented in this file. + +## 1.0.0 - 2024-11-28 +#### Census Service +The Census Service introduces core functionalities for managing census data: + +1. Validation of Census: Ensures data integrity by validating all census requests before processing. +2. Census Create: Creates new census records after validation and enrichment, publishing request to the designated Kafka topic to handle the creation process asynchronously. +3. Census Update: Updates existing records post-validation and enrichment by sending request to the designated Kafka update topic. +4. Census Bulk Update: Updates multiple census records in one operation after successful validation. +5. Census Search: Enables searching for census records with the provided search criteria. +6. Plan Facility Consumer: Listens to Plan Facility Update topic to assign facility to a boundary in census. \ No newline at end of file diff --git a/health-services/census-service/README.md b/health-services/census-service/README.md new file mode 100644 index 00000000000..a2e8a9f7b84 --- /dev/null +++ b/health-services/census-service/README.md @@ -0,0 +1,18 @@ +# Swagger generated server + +Spring Boot Server + + +## Overview +This server was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. +By using the [OpenAPI-Spec](https://github.com/swagger-api/swagger-core), you can easily generate a server stub. +This is an example of building a swagger-enabled server in Java using the SpringBoot framework. + +The underlying library integrating swagger to SpringBoot is [springfox](https://github.com/springfox/springfox) + +Start your server as an simple java application + +You can view the api documentation in swagger-ui by pointing to +http://localhost:8080/ + +Change default port value in application.properties \ No newline at end of file diff --git a/health-services/census-service/pom.xml b/health-services/census-service/pom.xml new file mode 100644 index 00000000000..7e6f7adc8fb --- /dev/null +++ b/health-services/census-service/pom.xml @@ -0,0 +1,141 @@ + + 4.0.0 + org.egov + census-service + jar + census-service + 1.0.0 + + 17 + ${java.version} + ${java.version} + + + org.springframework.boot + spring-boot-starter-parent + 3.2.2 + + + src/main/java + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.egov.common + health-services-models + 1.0.21-SNAPSHOT + compile + + + junit + junit + 4.13.2 + test + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.flywaydb + flyway-core + 9.22.3 + + + org.postgresql + postgresql + 42.7.1 + + + org.springframework.boot + spring-boot-starter-test + test + + + + io.swagger + swagger-core + 1.5.18 + + + io.swagger.core.v3 + swagger-annotations + 2.2.8 + + + net.minidev + json-smart + 2.5.0 + + + + org.egov.services + tracer + 2.9.0-SNAPSHOT + + + + + + + + org.egov + mdms-client + 2.9.0-SNAPSHOT + compile + + + org.projectlombok + lombok + true + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + org.springframework.boot + spring-boot-starter-validation + + + + + repo.egovernments.org + eGov ERP Releases Repository + https://nexus-repo.egovernments.org/nexus/content/repositories/releases/ + + + repo.egovernments.org.snapshots + eGov ERP Releases Repository + https://nexus-repo.egovernments.org/nexus/content/repositories/snapshots/ + + + repo.egovernments.org.public + eGov Public Repository Group + https://nexus-repo.egovernments.org/nexus/content/groups/public/ + + + repo.digit.org + eGov DIGIT Releases Repository + https://nexus-repo.digit.org/nexus/content/repositories/snapshots/ + + + diff --git a/health-services/census-service/src/main/java/digit/Main.java b/health-services/census-service/src/main/java/digit/Main.java new file mode 100644 index 00000000000..6e3d79db11c --- /dev/null +++ b/health-services/census-service/src/main/java/digit/Main.java @@ -0,0 +1,20 @@ +package digit; + + +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; + +@Import({ TracerConfiguration.class }) +@SpringBootApplication +@ComponentScan(basePackages = { "digit", "digit.web.controllers" , "digit.config"}) +public class Main { + + + public static void main(String[] args) throws Exception { + SpringApplication.run(Main.class, args); + } + +} diff --git a/health-services/census-service/src/main/java/digit/config/Configuration.java b/health-services/census-service/src/main/java/digit/config/Configuration.java new file mode 100644 index 00000000000..8459885357e --- /dev/null +++ b/health-services/census-service/src/main/java/digit/config/Configuration.java @@ -0,0 +1,86 @@ +package digit.config; + +import lombok.*; +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Import; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +@Data +@Import({TracerConfiguration.class}) +@NoArgsConstructor +@AllArgsConstructor +@Setter +@Getter +public class Configuration { + + // Allowed roles for census + @Value("#{${allowed.census.roles}}") + private List allowedCensusRoles; + + @Value("#{${workflow.restricted.roles}}") + private List workflowRestrictedRoles; + + // Persister Topic + @Value("${census.create.topic}") + private String censusCreateTopic; + + @Value("${census.update.topic}") + private String censusUpdateTopic; + + @Value("${census.bulk.update.topic}") + private String censusBulkUpdateTopic; + + @Value("${plan.facility.update.topic}") + private String planFcailityUpdateTopic; + + // Boundary Service + @Value("${egov.boundary.service.host}") + private String boundaryServiceHost; + + @Value("${egov.boundary.relationship.search.endpoint}") + private String boundaryRelationshipSearchEndpoint; + + @Value("${egov.boundary.hierarchy.search.endpoint}") + private String boundaryHierarchySearchEndpoint; + + // Plan Service + @Value("${egov.plan.service.host}") + private String planServiceHost; + + @Value("${egov.plan.employee.assignment.search.endpoint}") + private String planEmployeeAssignmentSearchEndpoint; + + //Workflow + @Value("${egov.workflow.host}") + private String wfHost; + + @Value("${egov.workflow.transition.path}") + private String wfTransitionPath; + + @Value("${egov.business.service.search.endpoint}") + private String businessServiceSearchEndpoint; + + @Value("${workflow.initiate.action}") + private List wfInitiateActions; + + @Value("${workflow.intermediate.action}") + private List wfIntermediateActions; + + @Value("${workflow.send.back.actions}") + private List wfSendBackActions; + + //SMSNotification + @Value("${egov.sms.notification.topic}") + private String smsNotificationTopic; + + //Pagination + @Value("${census.default.offset}") + private Integer defaultOffset; + + @Value("${census.default.limit}") + private Integer defaultLimit; +} diff --git a/health-services/census-service/src/main/java/digit/config/MainConfiguration.java b/health-services/census-service/src/main/java/digit/config/MainConfiguration.java new file mode 100644 index 00000000000..239331c9cd8 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/config/MainConfiguration.java @@ -0,0 +1,41 @@ +package digit.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; + +import java.util.TimeZone; + +import jakarta.annotation.PostConstruct; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.tracer.config.TracerConfiguration; + + +@Import({TracerConfiguration.class}) +public class MainConfiguration { + + @Value("${app.timezone}") + private String timeZone; + + @PostConstruct + public void initialize() { + TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); + } + + @Bean + public ObjectMapper objectMapper() { + return new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).setTimeZone(TimeZone.getTimeZone(timeZone)); + } + + @Bean + @Autowired + public MappingJackson2HttpMessageConverter jacksonConverter(ObjectMapper objectMapper) { + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + converter.setObjectMapper(objectMapper); + return converter; + } +} \ No newline at end of file diff --git a/health-services/census-service/src/main/java/digit/config/ServiceConstants.java b/health-services/census-service/src/main/java/digit/config/ServiceConstants.java new file mode 100644 index 00000000000..5d944060848 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/config/ServiceConstants.java @@ -0,0 +1,114 @@ +package digit.config; + + +import org.springframework.stereotype.Component; + + +@Component +public class ServiceConstants { + + public static final String EXTERNAL_SERVICE_EXCEPTION = "External Service threw an Exception: "; + public static final String SEARCHER_SERVICE_EXCEPTION = "Exception while fetching from searcher: "; + + public static final String IDGEN_ERROR = "IDGEN ERROR"; + public static final String NO_IDS_FOUND_ERROR = "No ids returned from idgen Service"; + + public static final String ERROR_WHILE_FETCHING_FROM_MDMS = "Exception occurred while fetching category lists from mdms: "; + + public static final String ERROR_WHILE_FETCHING_BOUNDARY_DETAILS = "Exception occurred while fetching boundary relationship from boundary service: "; + + public static final String ERROR_WHILE_FETCHING_BOUNDARY_HIERARCHY_DETAILS = "Exception occurred while fetching boundary hierarchy details from boundary service: "; + + public static final String ERROR_WHILE_FETCHING_EMPLOYEE_ASSIGNMENT_DETAILS = "Exception occurred while fetching plan employee assignment details from plan service: "; + + public static final String ERROR_WHILE_FETCHING_BUSINESS_SERVICE_DETAILS = "Exception occurred while fetching business service details: "; + + public static final String RES_MSG_ID = "uief87324"; + public static final String SUCCESSFUL = "successful"; + public static final String FAILED = "failed"; + + public static final String URL = "url"; + public static final String URL_SHORTENING_ERROR_CODE = "URL_SHORTENING_ERROR"; + public static final String URL_SHORTENING_ERROR_MESSAGE = "Unable to shorten url: "; + + public static final String DOB_FORMAT_Y_M_D = "yyyy-MM-dd"; + public static final String DOB_FORMAT_D_M_Y = "dd/MM/yyyy"; + public static final String ILLEGAL_ARGUMENT_EXCEPTION_CODE = "IllegalArgumentException"; + public static final String OBJECTMAPPER_UNABLE_TO_CONVERT = "ObjectMapper not able to convertValue in userCall"; + public static final String DOB_FORMAT_D_M_Y_H_M_S = "dd-MM-yyyy HH:mm:ss"; + public static final String CREATED_DATE = "createdDate"; + public static final String LAST_MODIFIED_DATE = "lastModifiedDate"; + public static final String DOB = "dob"; + public static final String PWD_EXPIRY_DATE = "pwdExpiryDate"; + public static final String INVALID_DATE_FORMAT_CODE = "INVALID_DATE_FORMAT"; + public static final String INVALID_DATE_FORMAT_MESSAGE = "Failed to parse date format in user"; + public static final String CITIZEN_UPPER = "CITIZEN"; + public static final String CITIZEN_LOWER = "Citizen"; + public static final String USER = "user"; + public static final String PIPE_REGEX = "\\|"; + public static final String FACILITY_ID_FIELD = "facilityId"; + public static final String FACILITY_NAME_FIELD = "facilityName"; + + public static final String PARSING_ERROR_CODE = "PARSING ERROR"; + public static final String PARSING_ERROR_MESSAGE = "Failed to parse JSON data from PGobject"; + + public static final String FAILED_TO_PARSE_BUSINESS_SERVICE_SEARCH = "Failed to parse response of workflow business service search"; + public static final String BUSINESS_SERVICE_NOT_FOUND = "BUSINESSSERVICE_NOT_FOUND"; + public static final String THE_BUSINESS_SERVICE = "The businessService "; + public static final String NOT_FOUND = " is not found"; + public static final String TENANTID = "?tenantId="; + public static final String BUSINESS_SERVICES = "&businessServices="; + + public static final String NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_CODE = "NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE"; + public static final String NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_MESSAGE = "Invalid or incorrect boundaryCode. No boundary data found."; + + public static final String NO_BUSINESS_SERVICE_DATA_FOUND_CODE = "NO_BUSINESS_SERVICE_DATA_FOUND"; + public static final String NO_BUSINESS_SERVICE_DATA_FOUND_MESSAGE = "Invalid or incorrect businessService. No business service data found."; + + public static final String USERINFO_MISSING_CODE = "USERINFO_MISSING"; + public static final String USERINFO_MISSING_MESSAGE = "UserInfo is missing in Request Info "; + + public static final String ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_CODE = "ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS"; + public static final String ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_MESSAGE = "Exception occurred while updating additional details : "; + + public static final String WORKFLOW_INTEGRATION_ERROR_CODE = "WORKFLOW_INTEGRATION_ERROR"; + public static final String WORKFLOW_INTEGRATION_ERROR_MESSAGE = "Exception occured while integrating with workflow : "; + + public static final String INVALID_PARTNER_CODE = "INVALID_PARTNER"; + public static final String INVALID_PARTNER_MESSAGE = "Invalid partner assignment or invalid jurisdiction of the assigned partner"; + + public static final String INVALID_CENSUS_CODE = "INVALID_CENSUS"; + public static final String INVALID_CENSUS_MESSAGE = "Provided census does not exist"; + + public static final String DUPLICATE_CENSUS_ID_IN_BULK_UPDATE_CODE = "DUPLICATE_CENSUS_ID_IN_BULK_UPDATE"; + public static final String DUPLICATE_CENSUS_ID_IN_BULK_UPDATE_MESSAGE = "Census provided in the bulk update request are not unique."; + + public static final String INVALID_SOURCE_OR_TENANT_ID_FOR_BULK_UPDATE_CODE = "INVALID_SOURCE_OR_TENANT_ID_FOR_BULK_UPDATE"; + public static final String INVALID_SOURCE_OR_TENANT_ID_FOR_BULK_UPDATE_MESSAGE = "Tenant id and source should be same across all entries for bulk update."; + + public static final String WORKFLOW_NOT_FOUND_FOR_BULK_UPDATE_CODE = "WORKFLOW_NOT_FOUND_FOR_BULK_UPDATE"; + public static final String WORKFLOW_NOT_FOUND_FOR_BULK_UPDATE_MESSAGE = "Workflow information is mandatory for each entry for bulk update"; + + public static final String DUPLICATE_KEY_IN_ADDITIONAL_FIELD_CODE = "DUPLICATE_KEY_IN_ADDITIONAL_FIELD"; + public static final String DUPLICATE_KEY_IN_ADDITIONAL_FIELD_MESSGAE = "Duplicate key found in additional field : "; + + public static final String CENSUS_ALREADY_EXISTS_CODE = "CENSUS_ALREADY_EXISTS"; + public static final String CENSUS_ALREADY_EXISTS_MESSAGE = "Census with the given boundary and source already exists."; + + public static final String DIFFERENT_WORKFLOW_FOR_BULK_UPDATE_CODE = "DIFFERENT_WORKFLOW_FOR_BULK_UPDATE"; + public static final String DIFFERENT_WORKFLOW_FOR_BULK_UPDATE_MESSAGE = "All entries should be in the same state for bulk transitioning census records."; + + public static final String UNAUTHORIZED_WORKFLOW_ACCESS_CODE = "UNAUTHORIZED_WORKFLOW_ACCESS"; + public static final String UNAUTHORIZED_WORKFLOW_ACCESS_MESSAGE = "User with provided roles cannot have an active workflow. Please remove the workflow or update user roles."; + + public static final String SEARCH_CRITERIA_EMPTY_CODE = "SEARCH_CRITERIA_EMPTY"; + public static final String SEARCH_CRITERIA_EMPTY_MESSAGE = "Search criteria cannot be empty"; + + public static final String TENANT_ID_EMPTY_CODE = "TENANT_ID_EMPTY"; + public static final String TENANT_ID_EMPTY_MESSAGE = "Tenant Id cannot be empty, TenantId should be present"; + + //Workflow constants + public static final String MODULE_NAME_VALUE = "census-service"; + + public static final String CENSUS_BUSINESS_SERVICE = "CENSUS"; +} diff --git a/health-services/census-service/src/main/java/digit/kafka/FacilityCatchmentConsumer.java b/health-services/census-service/src/main/java/digit/kafka/FacilityCatchmentConsumer.java new file mode 100644 index 00000000000..d5be4b7458c --- /dev/null +++ b/health-services/census-service/src/main/java/digit/kafka/FacilityCatchmentConsumer.java @@ -0,0 +1,99 @@ +package digit.kafka; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.repository.CensusRepository; +import digit.service.CensusService; +import digit.service.enrichment.CensusEnrichment; +import digit.util.BoundaryUtil; +import digit.util.CommonUtil; +import digit.web.models.BulkCensusRequest; +import digit.web.models.Census; +import digit.web.models.CensusResponse; +import digit.web.models.boundary.BoundaryTypeHierarchyResponse; +import digit.web.models.plan.PlanFacilityDTO; +import digit.web.models.plan.PlanFacilityRequestDTO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Component; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static digit.config.ServiceConstants.FACILITY_ID_FIELD; +import static digit.config.ServiceConstants.FACILITY_NAME_FIELD; + +@Component +@Slf4j +public class FacilityCatchmentConsumer { + + private ObjectMapper objectMapper; + + private CensusService service; + + private CensusRepository repository; + + private CommonUtil commonUtil; + + private BoundaryUtil boundaryUtil; + + private CensusEnrichment enrichment; + + public FacilityCatchmentConsumer(ObjectMapper objectMapper, CensusService service, CommonUtil commonUtil, CensusRepository repository, BoundaryUtil boundaryUtil, CensusEnrichment enrichment) { + this.objectMapper = objectMapper; + this.service = service; + this.commonUtil = commonUtil; + this.repository = repository; + this.boundaryUtil = boundaryUtil; + this.enrichment = enrichment; + } + + @KafkaListener(topics = {"${plan.facility.update.topic}"}) + public void listen(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + PlanFacilityRequestDTO planFacilityRequestDTO = objectMapper.convertValue(consumerRecord, PlanFacilityRequestDTO.class); + PlanFacilityDTO planFacilityDTO = planFacilityRequestDTO.getPlanFacilityDTO(); + + CensusResponse censusResponse = service.search(commonUtil.getCensusSearchRequest(planFacilityDTO.getTenantId(), planFacilityDTO.getPlanConfigurationId(), planFacilityDTO.getServiceBoundaries(), planFacilityDTO.getInitiallySetServiceBoundaries(), planFacilityRequestDTO.getRequestInfo())); + List censusFromSearch = censusResponse.getCensus(); + + BoundaryTypeHierarchyResponse boundaryTypeHierarchyResponse = boundaryUtil.fetchBoundaryHierarchy(planFacilityRequestDTO.getRequestInfo(), censusFromSearch.get(0).getTenantId(), censusFromSearch.get(0).getHierarchyType()); + String facilityId = planFacilityRequestDTO.getPlanFacilityDTO().getFacilityId(); + String facilityName = planFacilityRequestDTO.getPlanFacilityDTO().getFacilityName(); + + Set boundariesWithFacility = new HashSet<>(List.of(planFacilityDTO.getServiceBoundaries().split(","))); + Set boundariesWithNoFacility = new HashSet<>(planFacilityDTO.getInitiallySetServiceBoundaries()); + + censusFromSearch.forEach(census -> { + String boundaryCode = census.getBoundaryCode(); + + if (!boundariesWithFacility.contains(boundaryCode)) { + + // Unassigning facilities to the boundaries which were initially assigned that facility + census.setAdditionalDetails(commonUtil.removeFieldFromAdditionalDetails(census.getAdditionalDetails(), FACILITY_ID_FIELD)); + census.setAdditionalDetails(commonUtil.removeFieldFromAdditionalDetails(census.getAdditionalDetails(), FACILITY_NAME_FIELD)); + census.setFacilityAssigned(Boolean.FALSE); + census.setPartnerAssignmentValidationEnabled(Boolean.FALSE); + + } else if (!boundariesWithNoFacility.contains(boundaryCode)) { + + // Assigning facilities to the newly added boundaries in the update request. + census.setAdditionalDetails(commonUtil.updateFieldInAdditionalDetails(census.getAdditionalDetails(), FACILITY_ID_FIELD, facilityId)); + census.setAdditionalDetails(commonUtil.updateFieldInAdditionalDetails(census.getAdditionalDetails(), FACILITY_NAME_FIELD, facilityName)); + census.setFacilityAssigned(Boolean.TRUE); + census.setPartnerAssignmentValidationEnabled(Boolean.FALSE); + } + }); + + // Enrich jurisdiction mapping in census for indexer + enrichment.enrichJurisdictionMapping(censusFromSearch, boundaryTypeHierarchyResponse.getBoundaryHierarchy().get(0)); + repository.bulkUpdate(BulkCensusRequest.builder().requestInfo(planFacilityRequestDTO.getRequestInfo()).census(censusFromSearch).build()); + + } catch (Exception exception) { + log.error("Error in census consumer", exception); + } + } +} diff --git a/health-services/census-service/src/main/java/digit/kafka/Producer.java b/health-services/census-service/src/main/java/digit/kafka/Producer.java new file mode 100644 index 00000000000..542f4f686c0 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/kafka/Producer.java @@ -0,0 +1,20 @@ +package digit.kafka; + +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.kafka.CustomKafkaTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +// NOTE: If tracer is disabled change CustomKafkaTemplate to KafkaTemplate in autowiring + +@Service +@Slf4j +public class Producer { + + @Autowired + private CustomKafkaTemplate kafkaTemplate; + + public void push(String topic, Object value) { + kafkaTemplate.send(topic, value); + } +} diff --git a/health-services/census-service/src/main/java/digit/kafka/ResourceCensusConsumer.java b/health-services/census-service/src/main/java/digit/kafka/ResourceCensusConsumer.java new file mode 100644 index 00000000000..e161225b23a --- /dev/null +++ b/health-services/census-service/src/main/java/digit/kafka/ResourceCensusConsumer.java @@ -0,0 +1,37 @@ +package digit.kafka; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.service.CensusService; +import digit.web.models.CensusRequest; +import lombok.extern.slf4j.Slf4j; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +@Slf4j +public class ResourceCensusConsumer { + + private CensusService censusService; + + private ObjectMapper mapper; + + public ResourceCensusConsumer(CensusService censusService, ObjectMapper mapper) { + this.censusService = censusService; + this.mapper = mapper; + } + + @KafkaListener(topics = {"${resource.config.consumer.census.create.topic}"}) + public void listen(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + CensusRequest censusRequest = mapper.convertValue(consumerRecord, CensusRequest.class); + censusRequest.getCensus().setPartnerAssignmentValidationEnabled(Boolean.FALSE); + censusService.create(censusRequest); + } catch (Exception exception) { + log.error("Error in resource census consumer", exception); + } + } +} diff --git a/health-services/census-service/src/main/java/digit/repository/CensusRepository.java b/health-services/census-service/src/main/java/digit/repository/CensusRepository.java new file mode 100644 index 00000000000..4a9f159e7e9 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/repository/CensusRepository.java @@ -0,0 +1,21 @@ +package digit.repository; + +import digit.web.models.*; + +import java.util.List; +import java.util.Map; + +public interface CensusRepository { + + public void create(CensusRequest censusRequest); + + public List search(CensusSearchCriteria censusSearchCriteria); + + public void update(CensusRequest censusRequest); + + public void bulkUpdate(BulkCensusRequest request); + + public Integer count(CensusSearchCriteria censusSearchCriteria); + + public Map statusCount(CensusSearchRequest censusSearchRequest); +} diff --git a/health-services/census-service/src/main/java/digit/repository/ServiceRequestRepository.java b/health-services/census-service/src/main/java/digit/repository/ServiceRequestRepository.java new file mode 100644 index 00000000000..d09d230e4fa --- /dev/null +++ b/health-services/census-service/src/main/java/digit/repository/ServiceRequestRepository.java @@ -0,0 +1,45 @@ +package digit.repository; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.model.ServiceCallException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import java.util.Map; + +import static digit.config.ServiceConstants.*; + +@Repository +@Slf4j +public class ServiceRequestRepository { + + private ObjectMapper mapper; + + private RestTemplate restTemplate; + + public ServiceRequestRepository(ObjectMapper mapper, RestTemplate restTemplate) { + this.mapper = mapper; + this.restTemplate = restTemplate; + } + + + public Object fetchResult(StringBuilder uri, Object request) { + mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + Object response = null; + try { + response = restTemplate.postForObject(uri.toString(), request, Map.class); + } catch (HttpClientErrorException e) { + log.error(EXTERNAL_SERVICE_EXCEPTION, e); + throw new ServiceCallException(e.getResponseBodyAsString()); + } catch (Exception e) { + log.error(SEARCHER_SERVICE_EXCEPTION, e); + } + + return response; + } +} \ No newline at end of file diff --git a/health-services/census-service/src/main/java/digit/repository/impl/CensusRepositoryImpl.java b/health-services/census-service/src/main/java/digit/repository/impl/CensusRepositoryImpl.java new file mode 100644 index 00000000000..c6dec4b4d11 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/repository/impl/CensusRepositoryImpl.java @@ -0,0 +1,219 @@ +package digit.repository.impl; + +import digit.config.Configuration; +import digit.kafka.Producer; +import digit.repository.CensusRepository; +import digit.repository.querybuilder.CensusQueryBuilder; +import digit.repository.rowmapper.CensusRowMapper; +import digit.repository.rowmapper.StatusCountRowMapper; +import digit.util.CommonUtil; +import digit.web.models.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.SingleColumnRowMapper; +import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static digit.config.ServiceConstants.CENSUS_BUSINESS_SERVICE; + +@Slf4j +@Repository +public class CensusRepositoryImpl implements CensusRepository { + + private Producer producer; + + private Configuration config; + + private CensusQueryBuilder queryBuilder; + + private CensusRowMapper censusRowMapper; + + private JdbcTemplate jdbcTemplate; + + private StatusCountRowMapper statusCountRowMapper; + + private CommonUtil commonUtil; + + public CensusRepositoryImpl(Producer producer, Configuration config, CensusQueryBuilder queryBuilder, CensusRowMapper censusRowMapper, JdbcTemplate jdbcTemplate, StatusCountRowMapper statusCountRowMapper,CommonUtil commonUtil) { + this.producer = producer; + this.config = config; + this.queryBuilder = queryBuilder; + this.censusRowMapper = censusRowMapper; + this.jdbcTemplate = jdbcTemplate; + this.statusCountRowMapper = statusCountRowMapper; + this.commonUtil = commonUtil; + } + + /** + * Pushes a new census record to persister kafka topic. + * + * @param censusRequest The request containing the census details + */ + @Override + public void create(CensusRequest censusRequest) { + CensusRequestDTO requestDTO = convertToReqDTO(censusRequest); + producer.push(config.getCensusCreateTopic(), requestDTO); + } + + /** + * Searches for census records based on the provided search criteria. + * + * @param censusSearchCriteria The criteria to use for searching census records. + * @return A list of census records that match the search criteria. + */ + @Override + public List search(CensusSearchCriteria censusSearchCriteria) { + + if(censusSearchCriteria.getAreaCodes() != null && censusSearchCriteria.getAreaCodes().isEmpty()) + return new ArrayList<>(); + + // Fetch census ids from database + List censusIds = queryDatabaseForCensusIds(censusSearchCriteria); + + // Return empty list back as response if no census ids are found + if(CollectionUtils.isEmpty(censusIds)) { + log.info("No census ids found for provided census search criteria."); + return new ArrayList<>(); + } + + // Fetch census from database based on the acquired ids + return searchCensusByIds(censusIds); + } + + private List searchCensusByIds(List censusIds) { + + List preparedStmtList = new ArrayList<>(); + String query = queryBuilder.getCensusQuery(censusIds, preparedStmtList); + log.info("Census query: " + query); + return jdbcTemplate.query(query, censusRowMapper, preparedStmtList.toArray()); + + } + + private List queryDatabaseForCensusIds(CensusSearchCriteria censusSearchCriteria) { + List preparedStmtList = new ArrayList<>(); + String query = queryBuilder.getCensusSearchQuery(censusSearchCriteria, preparedStmtList); + log.info("Census search query: " + query); + return jdbcTemplate.query(query, new SingleColumnRowMapper<>(String.class), preparedStmtList.toArray()); + } + + /** + * Counts the number of census records based on the provided search criteria. + * + * @param censusSearchCriteria The search criteria for filtering census records. + * @return The total count of census matching the search criteria. + */ + @Override + public Integer count(CensusSearchCriteria censusSearchCriteria) { + + if(censusSearchCriteria.getAreaCodes() != null && censusSearchCriteria.getAreaCodes().isEmpty()) + return 0; + + List preparedStmtList = new ArrayList<>(); + String query = queryBuilder.getCensusCountQuery(censusSearchCriteria, preparedStmtList); + + return jdbcTemplate.queryForObject(query, preparedStmtList.toArray(), Integer.class); + } + + /** + * Counts the census record based on their current status for the provided search criteria. + * + * @param censusSearchRequest The request with search criteria for filtering census records. + * @return The status count of census records for the given search criteria. + */ + @Override + public Map statusCount(CensusSearchRequest censusSearchRequest) { + List preparedStmtList = new ArrayList<>(); + List statusList = commonUtil.getStatusFromBusinessService(censusSearchRequest.getRequestInfo(), CENSUS_BUSINESS_SERVICE, censusSearchRequest.getCensusSearchCriteria().getTenantId()); + + String query = queryBuilder.getCensusStatusCountQuery(censusSearchRequest.getCensusSearchCriteria(), preparedStmtList); + Map statusCountMap = jdbcTemplate.query(query, statusCountRowMapper, preparedStmtList.toArray()); + + statusList.forEach(status -> { + if(ObjectUtils.isEmpty(statusCountMap.get(status))) + statusCountMap.put(status, 0); + }); + + return statusCountMap; + } + + /** + * Pushes an updated existing census record to persister kafka topic. + * + * @param censusRequest The request containing the updated census details + */ + @Override + public void update(CensusRequest censusRequest) { + CensusRequestDTO requestDTO = convertToReqDTO(censusRequest); + producer.push(config.getCensusUpdateTopic(), requestDTO); + } + + /** + * Updates workflow status of a list of census records. + * + * @param request The bulk request containing the census records. + */ + @Override + public void bulkUpdate(BulkCensusRequest request) { + // Get bulk census update query + String bulkCensusUpdateQuery = queryBuilder.getBulkCensusQuery(); + + // Prepare rows for bulk update + List rows = request.getCensus().stream().map(census -> new Object[] { + census.getStatus(), + !CollectionUtils.isEmpty(census.getAssignee()) ? String.join(",", census.getAssignee()) : census.getAssignee(), + census.getAuditDetails().getLastModifiedBy(), + census.getAuditDetails().getLastModifiedTime(), + commonUtil.convertToPgObject(census.getAdditionalDetails()), + census.getFacilityAssigned(), + census.getId() + }).toList(); + + // Perform bulk update + jdbcTemplate.batchUpdate(bulkCensusUpdateQuery, rows); + producer.push(config.getCensusBulkUpdateTopic(), request); + } + + /** + * Converts the CensusRequest to a data transfer object (DTO) + * + * @param censusRequest The request to be converted to DTO + * @return a DTO for CensusRequest + */ + private CensusRequestDTO convertToReqDTO(CensusRequest censusRequest) { + Census census = censusRequest.getCensus(); + + String assignee = !CollectionUtils.isEmpty(census.getAssignee()) ? String.join(",", census.getAssignee()) : null; + + // Creating a new data transfer object (DTO) for Census + CensusDTO censusDTO = CensusDTO.builder() + .id(census.getId()) + .tenantId(census.getTenantId()) + .hierarchyType(census.getHierarchyType()) + .boundaryCode(census.getBoundaryCode()) + .assignee(assignee) + .status(census.getStatus()) + .type(census.getType().toString()) + .totalPopulation(census.getTotalPopulation()) + .populationByDemographics(census.getPopulationByDemographics()) + .jurisdictionMapping(census.getJurisdictionMapping()) + .additionalFields(census.getAdditionalFields()) + .effectiveFrom(census.getEffectiveFrom()) + .effectiveTo(census.getEffectiveTo()) + .source(census.getSource()) + .boundaryAncestralPath(census.getBoundaryAncestralPath().get(0)) + .facilityAssigned(census.getFacilityAssigned()) + .additionalDetails(census.getAdditionalDetails()) + .auditDetails(census.getAuditDetails()) + .build(); + + return CensusRequestDTO.builder() + .requestInfo(censusRequest.getRequestInfo()) + .censusDTO(censusDTO) + .build(); + } +} diff --git a/health-services/census-service/src/main/java/digit/repository/querybuilder/CensusQueryBuilder.java b/health-services/census-service/src/main/java/digit/repository/querybuilder/CensusQueryBuilder.java new file mode 100644 index 00000000000..7eec3f639ca --- /dev/null +++ b/health-services/census-service/src/main/java/digit/repository/querybuilder/CensusQueryBuilder.java @@ -0,0 +1,219 @@ +package digit.repository.querybuilder; + +import digit.config.Configuration; +import digit.util.QueryUtil; +import digit.web.models.CensusSearchCriteria; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; + +@Component +public class CensusQueryBuilder { + + private QueryUtil queryUtil; + + private Configuration config; + + public CensusQueryBuilder(QueryUtil queryUtil, Configuration config) { + this.config = config; + this.queryUtil = queryUtil; + } + + private static final String CENSUS_SEARCH_BASE_QUERY = "SELECT id FROM census cen"; + + private static final String CENSUS_QUERY = "SELECT cen.id as census_id, cen.tenant_id as census_tenant_id, cen.hierarchy_type as census_hierarchy_type, cen.boundary_code as census_boundary_code, cen.type as census_type, cen.total_population as census_total_population, cen.effective_from as census_effective_from, cen.effective_to as census_effective_to, cen.source as census_source, cen.status as census_status, cen.assignee as census_assignee, cen.boundary_ancestral_path as census_boundary_ancestral_path, cen.facility_assigned as census_facility_assigned, cen.additional_details as census_additional_details, cen.created_by as census_created_by, cen.created_time as census_created_time, cen.last_modified_by as census_last_modified_by, cen.last_modified_time as census_last_modified_time, \n" + + "\t pbd.id as population_by_demographics_id, pbd.census_id as population_by_demographics_census_id, pbd.demographic_variable as population_by_demographics_demographic_variable, pbd.population_distribution as population_by_demographics_population_distribution, pbd.created_by as population_by_demographics_created_by, pbd.created_time as population_by_demographics_created_time, pbd.last_modified_by as population_by_demographics_last_modified_by, pbd.last_modified_time as population_by_demographics_last_modified_time, \n" + + "\t adf.id as additional_field_id, adf.census_id as additional_field_census_id, adf.key as additional_field_key, adf.value as additional_field_value, adf.show_on_ui as additional_field_show_on_ui, adf.editable as additional_field_editable, adf.order as additional_field_order \n" + + "\t FROM census cen \n" + + "\t LEFT JOIN population_by_demographics pbd ON cen.id = pbd.census_id \n" + + "\t LEFT JOIN additional_field adf ON cen.id = adf.census_id"; + + private static final String CENSUS_SEARCH_QUERY_ORDER_BY_CLAUSE = " ORDER BY cen.last_modified_time DESC"; + + private static final String CENSUS_SEARCH_QUERY_COUNT_WRAPPER = "SELECT COUNT(id) AS total_count FROM ( "; + + private static final String CENSUS_STATUS_COUNT_QUERY = "SELECT COUNT(id) as census_status_count, status as census_status FROM (SELECT id, status FROM census {INTERNAL_QUERY}) as census_status_map GROUP BY census_status"; + + private static final String BULK_CENSUS_UPDATE_QUERY = "UPDATE census SET status = ?, assignee = ?, last_modified_by = ?, last_modified_time = ?, additional_details = ?, facility_assigned = ? WHERE id = ?"; + + /** + * Constructs a SQL query string for searching Census records based on the provided search criteria. + * Also adds an ORDER BY clause and handles pagination. + * + * @param ids The census ids used for filtering Census records. + * @param preparedStmtList A list to store prepared statement parameters. + * @return A complete SQL query string for searching Census records. + */ + public String getCensusQuery(List ids, List preparedStmtList) { + String query = buildCensusQuery(ids, preparedStmtList); + query = queryUtil.addOrderByClause(query, CENSUS_SEARCH_QUERY_ORDER_BY_CLAUSE); + return query; + } + + private String buildCensusQuery(List ids, List preparedStmtList) { + StringBuilder builder = new StringBuilder(CENSUS_QUERY); + + if (!CollectionUtils.isEmpty(ids)) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" cen.id IN ( ").append(queryUtil.createQuery(ids.size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, ids); + } + + return builder.toString(); + } + + public String getCensusSearchQuery(CensusSearchCriteria censusSearchCriteria, List preparedStmtList) { + String query = buildCensusSearchQuery(censusSearchCriteria, preparedStmtList, Boolean.FALSE, Boolean.FALSE); + query = queryUtil.addOrderByClause(query, CENSUS_SEARCH_QUERY_ORDER_BY_CLAUSE); + query = getPaginatedQuery(query, preparedStmtList, censusSearchCriteria); + return query; + } + + /** + * Constructs the count query to get the total count of census based on search criteria. + * + * @param searchCriteria The criteria used for filtering Census records. + * @param preparedStmtList A list to store prepared statement parameters. + * @return A SQL query string to get the total count of Census records for a given search criteria. + */ + public String getCensusCountQuery(CensusSearchCriteria searchCriteria, List preparedStmtList) { + return buildCensusSearchQuery(searchCriteria, preparedStmtList, Boolean.TRUE, Boolean.FALSE); + } + + /** + * Constructs the status count query to get the count of census based on their current status for the given search criteria + * + * @param searchCriteria The criteria used for filtering Census records. + * @param preparedStmtList A list to store prepared statement parameters. + * @return A SQL query string to get the status count of Census records for a given search criteria. + */ + public String getCensusStatusCountQuery(CensusSearchCriteria searchCriteria, List preparedStmtList) { + CensusSearchCriteria censusSearchCriteria = CensusSearchCriteria.builder().tenantId(searchCriteria.getTenantId()).source(searchCriteria.getSource()).jurisdiction(searchCriteria.getJurisdiction()).build(); + return buildCensusSearchQuery(censusSearchCriteria, preparedStmtList, Boolean.FALSE, Boolean.TRUE); + } + + /** + * Constructs query based on the provided search criteria + * + * @param criteria The criteria used for filtering Census ids. + * @param preparedStmtList A list to store prepared statement parameters. + * @return SQL query string for searching Census ids based on search criteria + */ + private String buildCensusSearchQuery(CensusSearchCriteria criteria, List preparedStmtList, Boolean isCount, Boolean isStatusCount) { + StringBuilder builder = new StringBuilder(CENSUS_SEARCH_BASE_QUERY); + + if(isStatusCount) { + builder = new StringBuilder(); + } + + if (!ObjectUtils.isEmpty(criteria.getId())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" id = ?"); + preparedStmtList.add(criteria.getId()); + } + + if (!CollectionUtils.isEmpty(criteria.getIds())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" id IN ( ").append(queryUtil.createQuery(criteria.getIds().size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, criteria.getIds()); + } + + if (!ObjectUtils.isEmpty(criteria.getTenantId())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" tenant_id = ?"); + preparedStmtList.add(criteria.getTenantId()); + } + + if (!ObjectUtils.isEmpty(criteria.getStatus())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" status = ?"); + preparedStmtList.add(criteria.getStatus()); + } + + if (!ObjectUtils.isEmpty(criteria.getSource())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" source = ?"); + preparedStmtList.add(criteria.getSource()); + } + + if (!ObjectUtils.isEmpty(criteria.getFacilityAssigned())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" facility_assigned = ?"); + preparedStmtList.add(criteria.getFacilityAssigned()); + } + + if (!ObjectUtils.isEmpty(criteria.getEffectiveTo())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + if (criteria.getEffectiveTo() == 0) { + builder.append(" effective_to IS NULL "); + } else { + builder.append(" effective_to = ?"); + preparedStmtList.add(criteria.getEffectiveTo()); + } + } + + if (!CollectionUtils.isEmpty(criteria.getAreaCodes())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" boundary_code IN ( ").append(queryUtil.createQuery(criteria.getAreaCodes().size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, criteria.getAreaCodes()); + } + + if (!ObjectUtils.isEmpty(criteria.getAssignee())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" ARRAY [ ").append(queryUtil.createQuery(Collections.singleton(criteria.getAssignee()).size())).append(" ]").append("::text[] "); + builder.append(" && string_to_array(assignee, ',') "); + queryUtil.addToPreparedStatement(preparedStmtList, Collections.singleton(criteria.getAssignee())); + } + + if (!CollectionUtils.isEmpty(criteria.getJurisdiction())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" ARRAY [ ").append(queryUtil.createQuery(criteria.getJurisdiction().size())).append(" ]").append("::text[] "); + builder.append(" && string_to_array(boundary_ancestral_path, '|') "); + queryUtil.addToPreparedStatement(preparedStmtList, criteria.getJurisdiction()); + } + + StringBuilder countQuery = new StringBuilder(); + if (isCount) { + countQuery.append(CENSUS_SEARCH_QUERY_COUNT_WRAPPER).append(builder); + countQuery.append(") AS subquery"); + + return countQuery.toString(); + } + + if (isStatusCount) { + return CENSUS_STATUS_COUNT_QUERY.replace("{INTERNAL_QUERY}", builder); + } + + return builder.toString(); + } + + public String getBulkCensusQuery() { + return BULK_CENSUS_UPDATE_QUERY; + } + + /** + * This method appends pagination i.e. limit and offset to the query. + * + * @param query the query to which pagination is to be added. + * @param preparedStmtList prepared statement list to add limit and offset. + * @return a query with pagination + */ + public String getPaginatedQuery(String query, List preparedStmtList, CensusSearchCriteria searchCriteria) { + StringBuilder paginatedQuery = new StringBuilder(query); + + // Append offset + paginatedQuery.append(" OFFSET ? "); + preparedStmtList.add(!ObjectUtils.isEmpty(searchCriteria.getOffset()) ? searchCriteria.getOffset() : config.getDefaultOffset()); + + // Append limit + paginatedQuery.append(" LIMIT ? "); + preparedStmtList.add(!ObjectUtils.isEmpty(searchCriteria.getLimit()) ? searchCriteria.getLimit() : config.getDefaultLimit()); + + return paginatedQuery.toString(); + } +} diff --git a/health-services/census-service/src/main/java/digit/repository/rowmapper/CensusRowMapper.java b/health-services/census-service/src/main/java/digit/repository/rowmapper/CensusRowMapper.java new file mode 100644 index 00000000000..7edac5005dd --- /dev/null +++ b/health-services/census-service/src/main/java/digit/repository/rowmapper/CensusRowMapper.java @@ -0,0 +1,148 @@ +package digit.repository.rowmapper; + +import digit.util.QueryUtil; +import digit.web.models.AdditionalField; +import digit.web.models.Census; +import digit.web.models.PopulationByDemographic; +import org.egov.common.contract.models.AuditDetails; +import org.postgresql.util.PGobject; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; + +@Component +public class CensusRowMapper implements ResultSetExtractor> { + + private QueryUtil queryUtil; + + public CensusRowMapper(QueryUtil queryUtil) { + this.queryUtil = queryUtil; + } + + /** + * Creates a list of Census record based on the ResultSet. + * + * @param rs the ResultSet containing data. + * @return a list of Census record + * @throws SQLException + * @throws DataAccessException + */ + @Override + public List extractData(ResultSet rs) throws SQLException, DataAccessException { + Map censusMap = new LinkedHashMap<>(); + Set populationByDemographicSet = new HashSet<>(); + Set additionalFieldSet = new HashSet<>(); + + while (rs.next()) { + String censusId = rs.getString("census_id"); + Census censusEntry = censusMap.get(censusId); + + if (ObjectUtils.isEmpty(censusEntry)) { + censusEntry = new Census(); + populationByDemographicSet.clear(); + additionalFieldSet.clear(); + + // Prepare audit details + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("census_created_by")).createdTime(rs.getLong("census_created_time")).lastModifiedBy(rs.getString("census_last_modified_by")).lastModifiedTime(rs.getLong("census_last_modified_time")).build(); + + String commaSeparatedAssignee = rs.getString("census_assignee"); + List assignee = !ObjectUtils.isEmpty(commaSeparatedAssignee) ? Arrays.asList(commaSeparatedAssignee.split(",")) : null; + + // Prepare census entry + censusEntry.setId(rs.getString("census_id")); + censusEntry.setTenantId(rs.getString("census_tenant_id")); + censusEntry.setHierarchyType(rs.getString("census_hierarchy_type")); + censusEntry.setBoundaryCode(rs.getString("census_boundary_code")); + censusEntry.setType(Census.TypeEnum.fromValue(rs.getString("census_type"))); + censusEntry.setTotalPopulation(rs.getLong("census_total_population")); + censusEntry.setEffectiveFrom(rs.getLong("census_effective_from")); + censusEntry.setEffectiveTo(rs.getLong("census_effective_to")); + censusEntry.setSource(rs.getString("census_source")); + censusEntry.setStatus(rs.getString("census_status")); + censusEntry.setAssignee(assignee); + censusEntry.setBoundaryAncestralPath(Collections.singletonList(rs.getString("census_boundary_ancestral_path"))); + censusEntry.setFacilityAssigned(rs.getBoolean("census_facility_assigned")); + censusEntry.setAdditionalDetails(queryUtil.parseJson((PGobject) rs.getObject("census_additional_details"))); + censusEntry.setAuditDetails(auditDetails); + } + addPopulationByDemographic(rs, populationByDemographicSet, censusEntry); + addAdditionalField(rs, additionalFieldSet, censusEntry); + + censusMap.put(censusId, censusEntry); + } + + return new ArrayList<>(censusMap.values()); + } + + /** + * Adds a AdditionalField object to the census entry based on the result set. + * + * @param rs The ResultSet containing the data. + * @param additionalFieldSet A set to keep track of added AdditionalField objects. + * @param censusEntry The Census entry to which the AdditionalField object will be added. + * @throws SQLException If an SQL error occurs. + */ + private void addAdditionalField(ResultSet rs, Set additionalFieldSet, Census censusEntry) throws SQLException { + String additionalFieldId = rs.getString("additional_field_id"); + + if (ObjectUtils.isEmpty(additionalFieldId) || additionalFieldSet.contains(additionalFieldId)) { + return; + } + + AdditionalField additionalField = new AdditionalField(); + additionalField.setId(rs.getString("additional_field_id")); + additionalField.setKey(rs.getString("additional_field_key")); + additionalField.setValue(rs.getBigDecimal("additional_field_value")); + additionalField.setShowOnUi(rs.getBoolean("additional_field_show_on_ui")); + additionalField.setEditable(rs.getBoolean("additional_field_editable")); + additionalField.setOrder(rs.getInt("additional_field_order")); + + if (CollectionUtils.isEmpty(censusEntry.getAdditionalFields())) { + List additionalFields = new ArrayList<>(); + additionalFields.add(additionalField); + censusEntry.setAdditionalFields(additionalFields); + } else { + censusEntry.getAdditionalFields().add(additionalField); + } + + additionalFieldSet.add(additionalFieldId); + } + + + /** + * Adds a PopulationByDemographics object to the census entry based on the result set. + * + * @param rs The ResultSet containing the data. + * @param populationByDemographicSet A set to keep track of added PopulationByDemographics objects. + * @param censusEntry The Census entry to which the PopulationByDemographics object will be added. + * @throws SQLException If an SQL error occurs. + */ + private void addPopulationByDemographic(ResultSet rs, Set populationByDemographicSet, Census censusEntry) throws SQLException { + String populationByDemographicId = rs.getString("population_by_demographics_id"); + + if (ObjectUtils.isEmpty(populationByDemographicId) || populationByDemographicSet.contains(populationByDemographicId)) { + return; + } + + PopulationByDemographic populationByDemographic = new PopulationByDemographic(); + populationByDemographic.setId(rs.getString("population_by_demographics_id")); + populationByDemographic.setDemographicVariable(PopulationByDemographic.DemographicVariableEnum.fromValue(rs.getString("population_by_demographics_demographic_variable"))); + populationByDemographic.setPopulationDistribution(queryUtil.parseJson((PGobject) rs.getObject("population_by_demographics_population_distribution"))); + + if (CollectionUtils.isEmpty(censusEntry.getPopulationByDemographics())) { + List populationByDemographicList = new ArrayList<>(); + populationByDemographicList.add(populationByDemographic); + censusEntry.setPopulationByDemographics(populationByDemographicList); + } else { + censusEntry.getPopulationByDemographics().add(populationByDemographic); + } + + populationByDemographicSet.add(populationByDemographicId); + } +} diff --git a/health-services/census-service/src/main/java/digit/repository/rowmapper/StatusCountRowMapper.java b/health-services/census-service/src/main/java/digit/repository/rowmapper/StatusCountRowMapper.java new file mode 100644 index 00000000000..b997f2f933f --- /dev/null +++ b/health-services/census-service/src/main/java/digit/repository/rowmapper/StatusCountRowMapper.java @@ -0,0 +1,30 @@ +package digit.repository.rowmapper; + +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +@Component +public class StatusCountRowMapper implements ResultSetExtractor> { + + @Override + public Map extractData(ResultSet rs) throws SQLException, DataAccessException { + Map statusCountMap = new HashMap<>(); + + while (rs.next()) { + String status = rs.getString("census_status"); + Integer statusCount = rs.getInt("census_status_count"); + + if(!ObjectUtils.isEmpty(status)) + statusCountMap.put(status, statusCount); + } + + return statusCountMap; + } +} diff --git a/health-services/census-service/src/main/java/digit/service/CensusService.java b/health-services/census-service/src/main/java/digit/service/CensusService.java new file mode 100644 index 00000000000..ec37824bfc1 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/service/CensusService.java @@ -0,0 +1,127 @@ +package digit.service; + +import digit.repository.CensusRepository; +import digit.service.enrichment.CensusEnrichment; +import digit.service.enrichment.CensusTimeframeEnrichment; +import digit.service.validator.CensusValidator; +import digit.service.workflow.WorkflowService; +import digit.util.ResponseInfoFactory; +import digit.web.models.BulkCensusRequest; +import digit.web.models.CensusRequest; +import digit.web.models.CensusResponse; +import digit.web.models.CensusSearchRequest; +import org.springframework.stereotype.Service; + +import java.util.Collections; + +@Service +public class CensusService { + + private ResponseInfoFactory responseInfoFactory; + + private CensusRepository repository; + + private CensusValidator validator; + + private CensusEnrichment enrichment; + + private CensusTimeframeEnrichment timeframeEnrichment; + + private WorkflowService workflow; + + public CensusService(ResponseInfoFactory responseInfoFactory, CensusRepository repository, CensusValidator validator, CensusEnrichment enrichment, CensusTimeframeEnrichment timeframeEnrichment, WorkflowService workflow) { + this.responseInfoFactory = responseInfoFactory; + this.repository = repository; + this.validator = validator; + this.enrichment = enrichment; + this.timeframeEnrichment = timeframeEnrichment; + this.workflow = workflow; + } + + /** + * Creates a new census record based on the provided request. + * + * @param request The request containing the census data. + * @return The created census reponse. + */ + public CensusResponse create(CensusRequest request) { + + // Validate census create request + validator.validateCreate(request); + + // Enrich census create request + enrichment.enrichCreate(request); + + // Enrich timeframe for previous census + timeframeEnrichment.enrichPreviousTimeframe(request); + + // Call workflow transition API for status update + workflow.invokeWorkflowForStatusUpdate(request); + + // Delegate creation request to repository + repository.create(request); + + return CensusResponse.builder() + .census(Collections.singletonList(request.getCensus())) + .responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(request.getRequestInfo(), true)) + .build(); + } + + /** + * Searches for census record based on the provided search criteria. + * + * @param request The search request containing the criteria. + * @return A list of census record that matches the search criteria. + */ + public CensusResponse search(CensusSearchRequest request) { + + return CensusResponse.builder() + .responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(request.getRequestInfo(), true)) + .census(repository.search(request.getCensusSearchCriteria())) + .totalCount(repository.count(request.getCensusSearchCriteria())) + .statusCount(repository.statusCount(request)) + .build(); + } + + /** + * Updates an existing census record based on the provided request. + * + * @param request The request containing the updated census data. + * @return The updated census response. + */ + public CensusResponse update(CensusRequest request) { + // Validate census update request + validator.validateUpdate(request); + + // Enrich census update request + enrichment.enrichUpdate(request); + + // Call workflow transition API for status update + workflow.invokeWorkflowForStatusUpdate(request); + + // Delegate update request to repository + repository.update(request); + + return CensusResponse.builder() + .census(Collections.singletonList(request.getCensus())) + .responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(request.getRequestInfo(), true)) + .build(); + } + + public CensusResponse bulkUpdate(BulkCensusRequest request) { + + // Validate census bulk update request + validator.validateBulkUpdate(request); + + // Call workflow transition for updating status and assignee + workflow.invokeWorkflowForStatusUpdate(request); + + // Delegate bulk update request to repository + repository.bulkUpdate(request); + + return CensusResponse.builder() + .census(request.getCensus()) + .responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(request.getRequestInfo(), true)) + .build(); + } +} diff --git a/health-services/census-service/src/main/java/digit/service/enrichment/CensusEnrichment.java b/health-services/census-service/src/main/java/digit/service/enrichment/CensusEnrichment.java new file mode 100644 index 00000000000..4754de26c4e --- /dev/null +++ b/health-services/census-service/src/main/java/digit/service/enrichment/CensusEnrichment.java @@ -0,0 +1,218 @@ +package digit.service.enrichment; + +import digit.util.CommonUtil; +import digit.web.models.AdditionalField; +import digit.web.models.Census; +import digit.web.models.CensusRequest; +import digit.web.models.boundary.BoundaryTypeHierarchy; +import digit.web.models.boundary.BoundaryTypeHierarchyDefinition; +import digit.web.models.boundary.EnrichedBoundary; +import digit.web.models.boundary.HierarchyRelation; +import org.egov.common.utils.UUIDEnrichmentUtil; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.util.*; +import java.util.stream.Collectors; + +import static org.egov.common.utils.AuditDetailsEnrichmentUtil.prepareAuditDetails; + +@Component +public class CensusEnrichment { + + private CommonUtil commonUtil; + + public CensusEnrichment(CommonUtil commonUtil) { + this.commonUtil = commonUtil; + } + + /** + * Enriches the CensusRequest for creating a new census record. + * Enriches the given census record with generated IDs for Census and PopulationByDemographics. + * Validates user information, enriches audit details and effectiveFrom for create operation. + * + * @param request The CensusRequest to be enriched. + * @throws CustomException if user information is missing in the request. + */ + public void enrichCreate(CensusRequest request) { + Census census = request.getCensus(); + + // Generate id for census record + UUIDEnrichmentUtil.enrichRandomUuid(census, "id"); + + // Generate id for PopulationByDemographics + if (!CollectionUtils.isEmpty(census.getPopulationByDemographics())) { + census.getPopulationByDemographics().forEach(populationByDemographics -> UUIDEnrichmentUtil.enrichRandomUuid(populationByDemographics, "id")); + } + + // Generate id for additionalFields + census.getAdditionalFields().forEach(additionalField -> UUIDEnrichmentUtil.enrichRandomUuid(additionalField, "id")); + + // Set audit details for census record + census.setAuditDetails(prepareAuditDetails(census.getAuditDetails(), request.getRequestInfo(), Boolean.TRUE)); + + // Enrich effectiveFrom for the census record + census.setEffectiveFrom(census.getAuditDetails().getCreatedTime()); + + denormalizeAdditionalFields(request.getCensus()); + } + + private void denormalizeAdditionalFields(Census census) { + Map fieldsToAdd = census.getAdditionalFields().stream() + .collect(Collectors.toMap(AdditionalField::getKey, AdditionalField::getValue)); + + census.setAdditionalDetails(commonUtil.updateFieldInAdditionalDetails(census.getAdditionalDetails(), fieldsToAdd)); + } + + /** + * Enriches the boundary ancestral path and jurisdiction mapping for the provided boundary code in the census request. + * + * @param census The census record whose boundary ancestral path has to be enriched. + * @param tenantBoundary boundary relationship from the boundary service for the given boundary code. + */ + public void enrichBoundaryAncestralPath(Census census, HierarchyRelation tenantBoundary) { + EnrichedBoundary boundary = tenantBoundary.getBoundary().get(0); + Map jurisdictionMapping = new LinkedHashMap<>(); + + StringBuilder boundaryAncestralPath = new StringBuilder(boundary.getCode()); + jurisdictionMapping.put(boundary.getBoundaryType(), boundary.getCode()); + + // Iterate through the child boundary until there are no more + while (!CollectionUtils.isEmpty(boundary.getChildren())) { + boundary = boundary.getChildren().get(0); + boundaryAncestralPath.append("|").append(boundary.getCode()); + jurisdictionMapping.put(boundary.getBoundaryType(), boundary.getCode()); + } + + // Setting the boundary ancestral path for the provided boundary + census.setBoundaryAncestralPath(Collections.singletonList(boundaryAncestralPath.toString())); + + // Setting jurisdiction mapping for the provided boundary + census.setJurisdictionMapping(jurisdictionMapping); + } + + /** + * Enriches the CensusRequest for updating an existing census record. + * This method enriches the census record for update, validates user information and enriches audit details for update operation. + * + * @param request The CensusRequest to be enriched. + * @throws CustomException if user information is missing in the request. + */ + public void enrichUpdate(CensusRequest request) { + Census census = request.getCensus(); + + // Generate id for populationByDemographics + if (!CollectionUtils.isEmpty(census.getPopulationByDemographics())) { + census.getPopulationByDemographics().forEach(populationByDemographics -> { + if (ObjectUtils.isEmpty(populationByDemographics.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(populationByDemographics, "id"); + } + }); + } + + //Generate id for additionalFields + census.getAdditionalFields().forEach(additionalField -> { + if (ObjectUtils.isEmpty(additionalField.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(additionalField, "id"); + } + }); + + // Set last modified time on update call + census.getAuditDetails().setLastModifiedTime(System.currentTimeMillis()); + + denormalizeAdditionalFields(request.getCensus()); + } + + /** + * Helper method to enrich boundary hierarchy mapping. + * Creates a mapping of parentBoundaryType to childBoundaryType from the boundaryTypeHierarchy search response. + * + * @param boundaryTypeHierarchyDef Search response from boundary hierarchy search. + * @param boundaryHierarchyMapping boundary hierarchy map to be enriched. + * @return returns the highest boundary hierarchy for the given hierarchy type. + */ + private String getBoundaryHierarchyMapping(BoundaryTypeHierarchyDefinition boundaryTypeHierarchyDef, Map boundaryHierarchyMapping) { + String highestBoundaryHierarchy = null; + + for (BoundaryTypeHierarchy boundaryTypeHierarchy : boundaryTypeHierarchyDef.getBoundaryHierarchy()) { + if (ObjectUtils.isEmpty(boundaryTypeHierarchy.getParentBoundaryType())) + highestBoundaryHierarchy = boundaryTypeHierarchy.getBoundaryType(); + else + boundaryHierarchyMapping.put(boundaryTypeHierarchy.getParentBoundaryType(), boundaryTypeHierarchy.getBoundaryType()); + } + + return highestBoundaryHierarchy; + } + + /** + * Enriches jurisdiction mapping in census for the given boundary ancestral path. + * + * @param census census data with boundary ancestral path. + * @param boundaryTypeHierarchyDef boundary hierarchy for the given hierarchy type. + */ + public void enrichJurisdictionMapping(Census census, BoundaryTypeHierarchyDefinition boundaryTypeHierarchyDef) { + Map boundaryHierarchyMapping = new HashMap<>(); + + // Enriches the boundaryHierarchyMapping and returns the highest boundary hierarchy for the given hierarchy type. + String highestBoundaryHierarchy = getBoundaryHierarchyMapping(boundaryTypeHierarchyDef, boundaryHierarchyMapping); + + Map jurisdictionMapping = new LinkedHashMap<>(); + String boundaryHierarchy = highestBoundaryHierarchy; + + // Get the list of boundary codes from pipe separated boundaryAncestralPath. + List boundaryCode = getBoundaryCodeFromAncestralPath(census.getBoundaryAncestralPath()); + + // Creates the mapping of boundary hierarchy with the corresponding boundary code. + for (String boundary : boundaryCode) { + jurisdictionMapping.put(boundaryHierarchy, boundary); + boundaryHierarchy = boundaryHierarchyMapping.get(boundaryHierarchy); + } + + census.setJurisdictionMapping(jurisdictionMapping); + } + + /** + * Enriches jurisdiction mapping for the list of census records for the given boundary ancestral path. + * + * @param censusList list of census data with boundary ancestral paths. + * @param boundaryTypeHierarchyDef boundary hierarchy for the given hierarchy type. + */ + public void enrichJurisdictionMapping(List censusList, BoundaryTypeHierarchyDefinition boundaryTypeHierarchyDef) { + Map boundaryHierarchyMapping = new HashMap<>(); + + // Enriches the boundaryHierarchyMapping and returns the highest boundary hierarchy for the given hierarchy type. + String highestBoundaryHierarchy = getBoundaryHierarchyMapping(boundaryTypeHierarchyDef, boundaryHierarchyMapping); + + for (Census census : censusList) { + + Map jurisdictionMapping = new LinkedHashMap<>(); + String boundaryHierarchy = highestBoundaryHierarchy; + + // Get the list of boundary codes from pipe separated boundaryAncestralPath. + List boundaryCode = getBoundaryCodeFromAncestralPath(census.getBoundaryAncestralPath()); + + // Creates the mapping of boundary hierarchy with the corresponding boundary code. + for (String boundary : boundaryCode) { + jurisdictionMapping.put(boundaryHierarchy, boundary); + boundaryHierarchy = boundaryHierarchyMapping.get(boundaryHierarchy); + } + + census.setJurisdictionMapping(jurisdictionMapping); + } + } + + /** + * Converts the boundaryAncestral path from a pipe separated string to an array of boundary codes. + * + * @param boundaryAncestralPath pipe separated boundaryAncestralPath. + * @return a list of boundary codes. + */ + private List getBoundaryCodeFromAncestralPath(List boundaryAncestralPath) { + if (CollectionUtils.isEmpty(boundaryAncestralPath)) { + return Collections.emptyList(); + } + return Arrays.asList(boundaryAncestralPath.get(0).split("\\|")); + } +} diff --git a/health-services/census-service/src/main/java/digit/service/enrichment/CensusTimeframeEnrichment.java b/health-services/census-service/src/main/java/digit/service/enrichment/CensusTimeframeEnrichment.java new file mode 100644 index 00000000000..fdd131957df --- /dev/null +++ b/health-services/census-service/src/main/java/digit/service/enrichment/CensusTimeframeEnrichment.java @@ -0,0 +1,47 @@ +package digit.service.enrichment; + +import digit.repository.CensusRepository; +import digit.web.models.Census; +import digit.web.models.CensusRequest; +import digit.web.models.CensusSearchCriteria; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.Collections; +import java.util.List; + +@Component +public class CensusTimeframeEnrichment { + + private CensusRepository repository; + + public CensusTimeframeEnrichment(CensusRepository repository) { + this.repository = repository; + } + + /** + * Enriches the effectiveTo of previous census records for the same boundary. + * + * @param request The census request. + */ + public void enrichPreviousTimeframe(CensusRequest request) { + Census census = request.getCensus(); + List censusList = repository.search(CensusSearchCriteria.builder().tenantId(census.getTenantId()).areaCodes(Collections.singletonList(census.getBoundaryCode())).effectiveTo(0L).build()); + + if (!CollectionUtils.isEmpty(censusList)) { + censusList.forEach(censusData -> { + censusData.setEffectiveTo(census.getAuditDetails().getCreatedTime()); + updatePreviousCensus(CensusRequest.builder().requestInfo(request.getRequestInfo()).census(censusData).build()); + }); + } + } + + /** + * Updates the timeframe of the previous census records. + * + * @param request the census to be updated. + */ + private void updatePreviousCensus(CensusRequest request) { + repository.update(request); + } +} diff --git a/health-services/census-service/src/main/java/digit/service/validator/CensusValidator.java b/health-services/census-service/src/main/java/digit/service/validator/CensusValidator.java new file mode 100644 index 00000000000..526e2445fb8 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/service/validator/CensusValidator.java @@ -0,0 +1,337 @@ +package digit.service.validator; + +import digit.config.Configuration; +import digit.repository.CensusRepository; +import digit.service.enrichment.CensusEnrichment; +import digit.util.BoundaryUtil; +import digit.util.PlanEmployeeAssignmnetUtil; +import digit.web.models.*; +import digit.web.models.boundary.BoundarySearchResponse; +import digit.web.models.boundary.BoundaryTypeHierarchyResponse; +import digit.web.models.boundary.HierarchyRelation; +import digit.web.models.plan.PlanEmployeeAssignmentResponse; +import digit.web.models.plan.PlanEmployeeAssignmentSearchCriteria; +import digit.web.models.plan.PlanEmployeeAssignmentSearchRequest; +import org.egov.common.contract.request.User; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.util.*; +import java.util.stream.Collectors; + +import static digit.config.ServiceConstants.*; + +@Component +public class CensusValidator { + + private BoundaryUtil boundaryUtil; + + private PlanEmployeeAssignmnetUtil employeeAssignmnetUtil; + + private Configuration configs; + + private CensusRepository repository; + + private CensusEnrichment enrichment; + + public CensusValidator(BoundaryUtil boundaryUtil, PlanEmployeeAssignmnetUtil employeeAssignmnetUtil, Configuration configs, CensusRepository repository, CensusEnrichment enrichment) { + this.boundaryUtil = boundaryUtil; + this.employeeAssignmnetUtil = employeeAssignmnetUtil; + this.configs = configs; + this.repository = repository; + this.enrichment = enrichment; + } + + /** + * Validates boundary cade, partner assignment and jurisdiction for census create request + * + * @param request The create request for census + */ + public void validateCreate(CensusRequest request) { + Census census = request.getCensus(); + BoundarySearchResponse boundarySearchResponse = boundaryUtil.fetchBoundaryData(request.getRequestInfo(), census.getBoundaryCode(), census.getTenantId(), census.getHierarchyType(), Boolean.TRUE, Boolean.FALSE); + + // Validate duplicate records for census + validateDuplicateRecords(census); + + // Validate boundary code against boundary service + validateBoundaryCode(boundarySearchResponse, census); + + // Validate partner assignment and jurisdiction against plan service + validatePartnerForCensus(request); + + // Validate keys in additional field + validateAdditionalFields(request); + } + + private void validateDuplicateRecords(Census census) { + List censusResponseFromSearch = repository.search(CensusSearchCriteria.builder().source(census.getSource()).areaCodes(Collections.singletonList(census.getBoundaryCode())).build()); + + if(!CollectionUtils.isEmpty(censusResponseFromSearch)) { + throw new CustomException(CENSUS_ALREADY_EXISTS_CODE, CENSUS_ALREADY_EXISTS_MESSAGE); + } + } + + private void validateAdditionalFields(CensusRequest request) { + Set additionalFieldKeys = new HashSet<>(); + + request.getCensus().getAdditionalFields().forEach(additionalField -> { + if(additionalFieldKeys.contains(additionalField.getKey())) { + throw new CustomException(DUPLICATE_KEY_IN_ADDITIONAL_FIELD_CODE, DUPLICATE_KEY_IN_ADDITIONAL_FIELD_MESSGAE + additionalField.getKey()); + } + additionalFieldKeys.add(additionalField.getKey()); + }); + } + + /** + * Validates the boundary code provided in census request against boundary service. + * + * @param boundarySearchResponse response from the boundary service. + * @param census Census record whose boundary code is to be validated. + */ + private void validateBoundaryCode(BoundarySearchResponse boundarySearchResponse, Census census) { + HierarchyRelation tenantBoundary = boundarySearchResponse.getTenantBoundary().get(0); + + if (CollectionUtils.isEmpty(tenantBoundary.getBoundary())) { + throw new CustomException(NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_CODE, NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_MESSAGE); + } + + // Enrich the boundary ancestral path and jurisdiction mapping for the provided boundary code + enrichment.enrichBoundaryAncestralPath(census, tenantBoundary); + } + + /** + * Validates partner assignment and jurisdiction against plan service + * Also validates the user information within the provided CensusRequest. + * + * @param request the census request + */ + private void validatePartnerForCensus(CensusRequest request) { + + Census census = request.getCensus(); + + // Validate the user information in the request + if (ObjectUtils.isEmpty(request.getRequestInfo().getUserInfo())) { + throw new CustomException(USERINFO_MISSING_CODE, USERINFO_MISSING_MESSAGE); + } + + if (census.getPartnerAssignmentValidationEnabled()) { + User userInfo = request.getRequestInfo().getUserInfo(); + List jurisdiction = Arrays.asList(request.getCensus().getBoundaryAncestralPath().get(0).split("\\|")); + + Set roles = new HashSet<>(configs.getAllowedCensusRoles()); + validateWorkflowAccess(userInfo, census, roles); + + PlanEmployeeAssignmentSearchCriteria searchCriteria = PlanEmployeeAssignmentSearchCriteria.builder() + .employeeId(Collections.singletonList(userInfo.getUuid())) + .planConfigurationId(request.getCensus().getSource()) + .tenantId(request.getCensus().getTenantId()) + .role(roles.stream().toList()) + .jurisdiction(jurisdiction) + .build(); + + PlanEmployeeAssignmentResponse employeeAssignmentResponse = employeeAssignmnetUtil.fetchPlanEmployeeAssignment(PlanEmployeeAssignmentSearchRequest.builder() + .requestInfo(request.getRequestInfo()) + .planEmployeeAssignmentSearchCriteria(searchCriteria) + .build()); + + if (CollectionUtils.isEmpty(employeeAssignmentResponse.getPlanEmployeeAssignment())) { + throw new CustomException(INVALID_PARTNER_CODE, INVALID_PARTNER_MESSAGE); + } + + //enrich jurisdiction of current assignee + request.getCensus().setAssigneeJurisdiction(employeeAssignmentResponse.getPlanEmployeeAssignment().get(0).getJurisdiction()); + } + } + + private void validateWorkflowAccess(User userInfo, Census census, Set roles) { + Boolean hasCensusRoles = userInfo.getRoles().stream() + .anyMatch(role -> configs.getAllowedCensusRoles().contains(role.getCode())); + + Boolean hasWfRestrictedRoles = userInfo.getRoles().stream() + .anyMatch(role -> configs.getWorkflowRestrictedRoles().contains(role.getCode())); + + if(hasWfRestrictedRoles) { + roles.addAll(configs.getWorkflowRestrictedRoles()); + + if(!hasCensusRoles && !ObjectUtils.isEmpty(census.getWorkflow())) + throw new CustomException(UNAUTHORIZED_WORKFLOW_ACCESS_CODE, UNAUTHORIZED_WORKFLOW_ACCESS_MESSAGE); + } + } + + /** + * Validates partner assignment and jurisdiction for census update request. + * + * @param request the update request for Census. + */ + public void validateUpdate(CensusRequest request) { + BoundaryTypeHierarchyResponse boundaryTypeHierarchyResponse = boundaryUtil.fetchBoundaryHierarchy(request.getRequestInfo(), request.getCensus().getTenantId(), request.getCensus().getHierarchyType()); + + // Validate if Census record to be updated exists + validateCensusExistence(request); + + // Validate partner assignment and jurisdiction against plan service + validatePartnerForCensus(request); + + // Validate keys in additional field + validateAdditionalFields(request); + + // Enrich jurisdiction mapping in census + enrichment.enrichJurisdictionMapping(request.getCensus(), boundaryTypeHierarchyResponse.getBoundaryHierarchy().get(0)); + } + + /** + * Validates the existence of census record in the repository + * + * @param request The request containing the census to be validated + */ + private void validateCensusExistence(CensusRequest request) { + Census census = request.getCensus(); + CensusSearchCriteria searchCriteria = CensusSearchCriteria.builder() + .id(census.getId()) + .build(); + + List censusList = repository.search(searchCriteria); + + if (CollectionUtils.isEmpty(censusList)) { + throw new CustomException(INVALID_CENSUS_CODE, INVALID_CENSUS_MESSAGE); + } + + request.getCensus().setBoundaryAncestralPath(censusList.get(0).getBoundaryAncestralPath()); + } + + /** + * Validates census records for bulk update. + * Validates the census attributes, checks if census records to be validated exist. + * Also validates the partner assignment and jurisdiction for the given census records. + * + * @param request the census bulk update request. + */ + public void validateBulkUpdate(BulkCensusRequest request) { + BoundaryTypeHierarchyResponse boundaryTypeHierarchyResponse = boundaryUtil.fetchBoundaryHierarchy(request.getRequestInfo(), request.getCensus().get(0).getTenantId(), request.getCensus().get(0).getHierarchyType()); + + // Validate attributes across each census in the bulk update request + validateCensusAttributes(request); + + // Validate if census in request body exists + validateCensusExistence(request); + + // Validate partner assignment and jurisdiction against plan service + validatePartnerForCensus(request); + + // Enrich jurisdiction mapping in census + enrichment.enrichJurisdictionMapping(request.getCensus(), boundaryTypeHierarchyResponse.getBoundaryHierarchy().get(0)); + } + + /** + * Validates partner assignment and jurisdiction against plan service + * Also validates the user information within the provided CensusRequest. + * + * @param request the census bulk update request + */ + private void validatePartnerForCensus(BulkCensusRequest request) { + + // Validate the user information in the request + if (ObjectUtils.isEmpty(request.getRequestInfo().getUserInfo())) { + throw new CustomException(USERINFO_MISSING_CODE, USERINFO_MISSING_MESSAGE); + } + + List jurisdiction = Arrays.asList(request.getCensus().get(0).getBoundaryAncestralPath().get(0).split("\\|")); + + PlanEmployeeAssignmentSearchCriteria searchCriteria = PlanEmployeeAssignmentSearchCriteria.builder() + .employeeId(Collections.singletonList(request.getRequestInfo().getUserInfo().getUuid())) + .planConfigurationId(request.getCensus().get(0).getSource()) + .tenantId(request.getCensus().get(0).getTenantId()) + .role(configs.getAllowedCensusRoles()) + .jurisdiction(jurisdiction) + .build(); + + PlanEmployeeAssignmentResponse employeeAssignmentResponse = employeeAssignmnetUtil.fetchPlanEmployeeAssignment(PlanEmployeeAssignmentSearchRequest.builder() + .requestInfo(request.getRequestInfo()) + .planEmployeeAssignmentSearchCriteria(searchCriteria) + .build()); + + if (CollectionUtils.isEmpty(employeeAssignmentResponse.getPlanEmployeeAssignment())) { + throw new CustomException(INVALID_PARTNER_CODE, INVALID_PARTNER_MESSAGE); + } + + //enrich jurisdiction of current assignee in all census records + request.getCensus().forEach(census -> census.setAssigneeJurisdiction(employeeAssignmentResponse.getPlanEmployeeAssignment().get(0).getJurisdiction())); + } + + /** + * Validates the existence of bulk census records in the repository + * + * @param request The request containing all the census records to be validated + */ + private void validateCensusExistence(BulkCensusRequest request) { + + // Get all census ids to validate existence + List censusListFromDatabase = repository.search(CensusSearchCriteria.builder() + .ids(request.getCensus().stream().map(Census::getId).collect(Collectors.toSet())) + .offset(0) + .limit(request.getCensus().size()) + .build()); + + // If census id provided is invalid, throw an exception + if (censusListFromDatabase.size() != request.getCensus().size()) { + throw new CustomException(INVALID_CENSUS_CODE, INVALID_CENSUS_MESSAGE); + } + + // Enrich boundary ancestral path for each census object being passed in the request + enrichBoundaryAncestralPath(request, censusListFromDatabase); + + } + + /** + * Enriches the census records with boundary ancestral path from repository. + * + * @param request bulk request with all census records. + * @param censusListFromDatabase existing census records from the repository. + */ + private void enrichBoundaryAncestralPath(BulkCensusRequest request, List censusListFromDatabase) { + Map censusIdVsBoundaryAncestralPathMap = censusListFromDatabase.stream() + .collect(Collectors.toMap(Census::getId, census -> census.getBoundaryAncestralPath().get(0))); + + request.getCensus().forEach(census -> + census.setBoundaryAncestralPath(Collections.singletonList(censusIdVsBoundaryAncestralPathMap + .get(census.getId()))) + ); + } + + /** + * Validates if census records provided in bulk update are unique. + * Checks if all the records have same source and tenant id. + * Also validates if records have same workflow status and action to be taken. + * + * @param request the census bulk update request + */ + private void validateCensusAttributes(BulkCensusRequest request) { + + if (request.getCensus().stream().map(Census::getId).collect(Collectors.toSet()).size() + != request.getCensus().size()) { + throw new CustomException(DUPLICATE_CENSUS_ID_IN_BULK_UPDATE_CODE, DUPLICATE_CENSUS_ID_IN_BULK_UPDATE_MESSAGE); + } + + if (!request.getCensus().stream().allMatch(census -> + census.getTenantId().equals(request.getCensus().get(0).getTenantId()) && + census.getSource().equals(request.getCensus().get(0).getSource()))) { + throw new CustomException(INVALID_SOURCE_OR_TENANT_ID_FOR_BULK_UPDATE_CODE, INVALID_SOURCE_OR_TENANT_ID_FOR_BULK_UPDATE_MESSAGE); + } + + request.getCensus().forEach(census -> { + if (ObjectUtils.isEmpty(census.getWorkflow())) { + throw new CustomException(WORKFLOW_NOT_FOUND_FOR_BULK_UPDATE_CODE, WORKFLOW_NOT_FOUND_FOR_BULK_UPDATE_MESSAGE); + } + }); + + if (!request.getCensus().stream().allMatch(census -> + census.getStatus().equals(request.getCensus().get(0).getStatus()) && + census.getWorkflow().getAction().equals(request.getCensus().get(0).getWorkflow().getAction()))) { + throw new CustomException(DIFFERENT_WORKFLOW_FOR_BULK_UPDATE_CODE, DIFFERENT_WORKFLOW_FOR_BULK_UPDATE_MESSAGE); + } + } +} + diff --git a/health-services/census-service/src/main/java/digit/service/workflow/WorkflowService.java b/health-services/census-service/src/main/java/digit/service/workflow/WorkflowService.java new file mode 100644 index 00000000000..e842c5dae29 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/service/workflow/WorkflowService.java @@ -0,0 +1,331 @@ +package digit.service.workflow; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.config.Configuration; +import digit.repository.ServiceRequestRepository; +import digit.util.PlanEmployeeAssignmnetUtil; +import digit.web.models.BulkCensusRequest; +import digit.web.models.Census; +import digit.web.models.CensusRequest; +import digit.web.models.plan.PlanEmployeeAssignmentResponse; +import digit.web.models.plan.PlanEmployeeAssignmentSearchCriteria; +import digit.web.models.plan.PlanEmployeeAssignmentSearchRequest; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.models.Workflow; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.request.User; +import org.egov.common.contract.workflow.*; +import org.egov.common.utils.AuditDetailsEnrichmentUtil; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.util.*; +import java.util.stream.Collectors; + +import static digit.config.ServiceConstants.*; + +@Service +@Slf4j +public class WorkflowService { + + private ServiceRequestRepository serviceRequestRepository; + + private Configuration config; + + private ObjectMapper mapper; + + private PlanEmployeeAssignmnetUtil planEmployeeAssignmnetUtil; + + public WorkflowService(ServiceRequestRepository serviceRequestRepository, Configuration config, ObjectMapper mapper, PlanEmployeeAssignmnetUtil planEmployeeAssignmnetUtil) { + this.serviceRequestRepository = serviceRequestRepository; + this.config = config; + this.mapper = mapper; + this.planEmployeeAssignmnetUtil = planEmployeeAssignmnetUtil; + } + + /** + * Integrates with the workflow for the given census request. + * If the action is null, it does not proceed with integration. + * + * @param censusRequest The request containing the census object to integrate with the workflow. + */ + public void invokeWorkflowForStatusUpdate(CensusRequest censusRequest) { + if (ObjectUtils.isEmpty(censusRequest.getCensus().getWorkflow())) + return; + + ProcessInstanceRequest processInstanceRequest = createWorkflowRequest(censusRequest); + ProcessInstanceResponse processInstanceResponse = callWorkflowTransition(processInstanceRequest); + + // Setting the status back to the census object from workflow response + censusRequest.getCensus().setStatus(processInstanceResponse.getProcessInstances().get(0).getState().getState()); + + // Enrich audit details after auto assignment is complete + censusRequest.getCensus().setAuditDetails(AuditDetailsEnrichmentUtil + .prepareAuditDetails(censusRequest.getCensus().getAuditDetails(), censusRequest.getRequestInfo(), Boolean.FALSE)); + + } + + /** + * Integrates with the workflow for the given bulk census request. + * + * @param request The request containing the list of census objects to integrate with the workflow. + */ + public void invokeWorkflowForStatusUpdate(BulkCensusRequest request) { + + ProcessInstanceRequest processInstanceRequest = createWorkflowRequest(request); + ProcessInstanceResponse processInstanceResponse = callWorkflowTransition(processInstanceRequest); + + enrichCensusPostTransition(processInstanceResponse, request); + } + + /** + * Enriches the census records in bulk update with audit details and workflow status. + * + * @param processInstanceResponse process instance response containing the current workflow status + * @param request the bulk census request + */ + private void enrichCensusPostTransition(ProcessInstanceResponse processInstanceResponse, BulkCensusRequest request) { + // Update status and audit information post transition + request.getCensus().forEach(census -> { + // Update status of Census + census.setStatus(processInstanceResponse.getProcessInstances().get(0).getState().getState()); + + // Update audit information of census + census.setAuditDetails(AuditDetailsEnrichmentUtil + .prepareAuditDetails(census.getAuditDetails(), request.getRequestInfo(), Boolean.FALSE)); + }); + } + + /** + * Creates a workflow request from the given list of census records in bulk request. + * + * @param request The request containing the list of census to create a workflow request. + * @return The constructed process instance request for the workflow. + */ + private ProcessInstanceRequest createWorkflowRequest(BulkCensusRequest request) { + List processInstanceList = new ArrayList<>(); + + // Perform auto assignment + List assignee = getAssigneeForAutoAssignment(request.getCensus().get(0), request.getRequestInfo()); + + for (Census census : request.getCensus()) { + if (config.getWfSendBackActions().contains(census.getWorkflow().getAction())) { + assignee = Collections.singletonList(census.getAuditDetails().getLastModifiedBy()); + } + + // Set assignee + if (!ObjectUtils.isEmpty(assignee)) + census.getWorkflow().setAssignes(assignee); + + census.setAssignee(assignee); + + // Create process instance object from census + ProcessInstance processInstance = ProcessInstance.builder() + .businessId(census.getId()) + .tenantId(census.getTenantId()) + .businessService(CENSUS_BUSINESS_SERVICE) + .moduleName(MODULE_NAME_VALUE) + .action(census.getWorkflow().getAction()) + .comment(census.getWorkflow().getComments()) + .documents(census.getWorkflow().getDocuments()) + .build(); + + // Enrich user list for process instance + enrichAssignesInProcessInstance(processInstance, census.getWorkflow()); + + // Add entry for bulk transition + processInstanceList.add(processInstance); + } + + return ProcessInstanceRequest.builder() + .requestInfo(request.getRequestInfo()) + .processInstances(processInstanceList) + .build(); + } + + /** + * Calls the workflow transition service and retrieves the process instance response. + * + * @param processInstanceRequest The request containing process instance details for the workflow transition. + * @return The response containing details of the process instances after the transition. + * @throws CustomException if there is an error during the workflow integration. + */ + public ProcessInstanceResponse callWorkflowTransition(ProcessInstanceRequest processInstanceRequest) { + ProcessInstanceResponse processInstanceResponse; + try { + Object response = serviceRequestRepository.fetchResult(getWorkflowTransitionUri(), processInstanceRequest); + processInstanceResponse = mapper.convertValue(response, ProcessInstanceResponse.class); + } catch (Exception e) { + throw new CustomException(WORKFLOW_INTEGRATION_ERROR_CODE, WORKFLOW_INTEGRATION_ERROR_MESSAGE + e.getMessage()); + } + + return processInstanceResponse; + } + + /** + * Creates a workflow request from the given census request. + * + * @param censusRequest The request containing the census to create a workflow request. + * @return The constructed process instance request for the workflow. + */ + public ProcessInstanceRequest createWorkflowRequest(CensusRequest censusRequest) { + Census census = censusRequest.getCensus(); + + // Create process instance object from census + ProcessInstance processInstance = ProcessInstance.builder() + .businessId(census.getId()) + .tenantId(census.getTenantId()) + .businessService(CENSUS_BUSINESS_SERVICE) + .moduleName(MODULE_NAME_VALUE) + .action(census.getWorkflow().getAction()) + .comment(census.getWorkflow().getComments()) + .documents(census.getWorkflow().getDocuments()) + .build(); + + // Perform auto assignment + List assignee = getAssigneeForAutoAssignment(census, censusRequest.getRequestInfo()); + + if (config.getWfSendBackActions().contains(census.getWorkflow().getAction())) { + assignee = Collections.singletonList(census.getAuditDetails().getLastModifiedBy()); + } + + // Set Assignee + if (!ObjectUtils.isEmpty(assignee)) + census.getWorkflow().setAssignes(assignee); + + census.setAssignee(assignee); + + // Enrich user for process instance + enrichAssignesInProcessInstance(processInstance, census.getWorkflow()); + + log.info("Process Instance assignes - " + processInstance.getAssignes()); + return ProcessInstanceRequest.builder() + .requestInfo(censusRequest.getRequestInfo()) + .processInstances(Collections.singletonList(processInstance)) + .build(); + } + + /** + * Enriches the process instance with assignees from the given workflow. + * + * @param processInstance The process instance to enrich with assignees. + * @param workflow The workflow containing assignees to be added to the process instance. + */ + public void enrichAssignesInProcessInstance(ProcessInstance processInstance, Workflow workflow) { + List userList = CollectionUtils.isEmpty(workflow.getAssignes()) + ? new LinkedList<>() + : workflow.getAssignes().stream() + .map(assignee -> User.builder().uuid(assignee).build()) + .toList(); + + processInstance.setAssignes(userList); + } + + /** + * Constructs the URI for the workflow service transition API. + * + * @return The StringBuilder containing the constructed workflow transition URI. + */ + private StringBuilder getWorkflowTransitionUri() { + return new StringBuilder().append(config.getWfHost()).append(config.getWfTransitionPath()); + } + + /** + * Returns a list of assignee based on the workflow action and jurisdiction hierarchy. + * Retrieves jurisdiction boundaries from the census request and searches for matching employee assignments. + * + * For INITIATE actions, assigns the employee from the lowest boundary. + * For INTERMEDIATE actions (non-ROOT_APPROVER), assigns an employee from a higher-level boundary. + * For SEND_BACK actions, assigns the last modified user. + * + * @param census the census object containing workflow and jurisdiction details + * @param requestInfo the requestInfo + */ + private List getAssigneeForAutoAssignment(Census census, RequestInfo requestInfo) { + String[] allHierarchiesBoundaryCodes = census.getBoundaryAncestralPath().get(0).split(PIPE_REGEX); + String[] hierarchiesBoundaryCodes = Arrays.copyOf(allHierarchiesBoundaryCodes, allHierarchiesBoundaryCodes.length - 1); + + PlanEmployeeAssignmentSearchCriteria planEmployeeAssignmentSearchCriteria = + PlanEmployeeAssignmentSearchCriteria.builder() + .tenantId(census.getTenantId()) + .jurisdiction(Arrays.stream(hierarchiesBoundaryCodes).toList()) + .planConfigurationId(census.getSource()) + .role(config.getAllowedCensusRoles()) + .build(); + + //search for plan-employee assignments for the ancestral hierarchy codes. + PlanEmployeeAssignmentResponse planEmployeeAssignmentResponse = planEmployeeAssignmnetUtil.fetchPlanEmployeeAssignment(PlanEmployeeAssignmentSearchRequest.builder() + .planEmployeeAssignmentSearchCriteria(planEmployeeAssignmentSearchCriteria) + .requestInfo(requestInfo).build()); + + // Create a map of jurisdiction to list of employeeIds + Map> jurisdictionToEmployeeMap = planEmployeeAssignmentResponse.getPlanEmployeeAssignment().stream() + .filter(assignment -> !CollectionUtils.isEmpty(assignment.getJurisdiction())) + .flatMap(assignment -> { + String employeeId = assignment.getEmployeeId(); + return assignment.getJurisdiction().stream() + .filter(jurisdiction -> Arrays.asList(hierarchiesBoundaryCodes).contains(jurisdiction)) + .map(jurisdiction -> new AbstractMap.SimpleEntry<>(jurisdiction, employeeId)); + }) + .collect(Collectors.groupingBy( + Map.Entry::getKey, // jurisdiction as the key + LinkedHashMap::new, // Preserve insertion order + Collectors.mapping( + Map.Entry::getValue, // employee IDs as values + Collectors.toList() // Collect employee IDs into a List + ) + )); + + List assignee = null; //assignee will remain null in case terminate actions are being taken + + String action = census.getWorkflow().getAction(); + if (config.getWfInitiateActions().contains(action)) { + for (int i = hierarchiesBoundaryCodes.length - 1; i >= 0; i--) { + assignee = jurisdictionToEmployeeMap.get(hierarchiesBoundaryCodes[i]); + if (assignee != null) + break; // Stop iterating once an assignee is found + } + } else if (config.getWfIntermediateActions().contains(action)) { + assignee = assignToHigherBoundaryLevel(hierarchiesBoundaryCodes, census, jurisdictionToEmployeeMap); + } + + return assignee; + } + + /** + * Assigns a list of employees from a higher-level jurisdiction in the hierarchy. + * Iterates through boundary codes, checking if they match the assignee's jurisdiction. + * If a higher-level boundary has an assigned employee, returns that employee's ID. + * + * @param heirarchysBoundaryCodes boundary codes representing the hierarchy + * @param census the census object with jurisdiction details + * @param jurisdictionToEmployeeMap map of jurisdiction codes to employee IDs + * @return the list of employee IDs from the higher boundary, or null if + */ + public List assignToHigherBoundaryLevel(String[] heirarchysBoundaryCodes, Census census, Map> jurisdictionToEmployeeMap) { + for (int i = heirarchysBoundaryCodes.length - 1; i >= 0; i--) { + String boundaryCode = heirarchysBoundaryCodes[i]; + + // Check if this boundary code is present in assigneeJurisdiction + if (census.getAssigneeJurisdiction().contains(boundaryCode)) { + + for (int j = i - 1; j >= 0; j--) { + // Check the next higher level in the hierarchy (one index above the match) + String higherBoundaryCode = heirarchysBoundaryCodes[j]; + + // Fetch the employeeId from the map for the higher boundary code + List employeeId = jurisdictionToEmployeeMap.get(higherBoundaryCode); + + // If an employee is found, set them as the assignee and break the loop + if (employeeId != null) { + return employeeId; + } + } + } + } + return null; + } + +} \ No newline at end of file diff --git a/health-services/census-service/src/main/java/digit/util/BoundaryUtil.java b/health-services/census-service/src/main/java/digit/util/BoundaryUtil.java new file mode 100644 index 00000000000..8e977cf3ccb --- /dev/null +++ b/health-services/census-service/src/main/java/digit/util/BoundaryUtil.java @@ -0,0 +1,111 @@ +package digit.util; + +import digit.config.Configuration; +import digit.web.models.RequestInfoWrapper; +import digit.web.models.boundary.BoundarySearchResponse; +import digit.web.models.boundary.BoundaryTypeHierarchyResponse; +import digit.web.models.boundary.BoundaryTypeHierarchySearchCriteria; +import digit.web.models.boundary.BoundaryTypeHierarchySearchRequest; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.util.HashMap; +import java.util.Map; + +import static digit.config.ServiceConstants.ERROR_WHILE_FETCHING_BOUNDARY_DETAILS; +import static digit.config.ServiceConstants.ERROR_WHILE_FETCHING_BOUNDARY_HIERARCHY_DETAILS; + +@Slf4j +@Component +public class BoundaryUtil { + + private RestTemplate restTemplate; + + private Configuration configs; + + public BoundaryUtil(RestTemplate restTemplate, Configuration configs) { + this.restTemplate = restTemplate; + this.configs = configs; + } + + /** + * This method fetches boundary relationships from Boundary service for the provided boundaryCode and hierarchyType. + * + * @param requestInfo request info from the request. + * @param boundaryCode boundary code from the request. + * @param tenantId tenant id from the request. + * @param hierarchyType hierarchy type from the request. + * @param includeParents is true if you want to include parent boundary. + * @param includeChildren is true if you want to include child boundary. + * @return returns the response from boundary service + */ + public BoundarySearchResponse fetchBoundaryData(RequestInfo requestInfo, String boundaryCode, String tenantId, String hierarchyType, Boolean includeParents, Boolean includeChildren) { + + // Create Boundary Relationship search uri + Map uriParameters = new HashMap<>(); + StringBuilder uri = getBoundaryRelationshipSearchUri(uriParameters, boundaryCode, tenantId, hierarchyType, includeParents, includeChildren); + + // Create request body + RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(requestInfo).build(); + BoundarySearchResponse boundarySearchResponse = new BoundarySearchResponse(); + + try { + boundarySearchResponse = restTemplate.postForObject(uri.toString(), requestInfoWrapper, BoundarySearchResponse.class, uriParameters); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_BOUNDARY_DETAILS, e); + } + + return boundarySearchResponse; + } + + /** + * This method creates Boundary service uri with query parameters + * + * @param uriParameters map that stores values corresponding to the placeholder in uri + * @param boundaryCode boundary code from the request. + * @param tenantId tenant id from the request. + * @param hierarchyType hierarchy type from the request. + * @param includeParents is true if you want to include parent boundary. + * @param includeChildren is true if you want to include child boundary. + * @return a complete boundary service uri + */ + private StringBuilder getBoundaryRelationshipSearchUri(Map uriParameters, String boundaryCode, String tenantId, String hierarchyType, Boolean includeParents, Boolean includeChildren) { + StringBuilder uri = new StringBuilder(); + uri.append(configs.getBoundaryServiceHost()).append(configs.getBoundaryRelationshipSearchEndpoint()).append("?codes={boundaryCode}&includeParents={includeParents}&includeChildren={includeChildren}&tenantId={tenantId}&hierarchyType={hierarchyType}"); + + uriParameters.put("boundaryCode", boundaryCode); + uriParameters.put("tenantId", tenantId); + uriParameters.put("includeParents", includeParents.toString()); + uriParameters.put("includeChildren", includeChildren.toString()); + uriParameters.put("hierarchyType", hierarchyType); + + return uri; + } + + public BoundaryTypeHierarchyResponse fetchBoundaryHierarchy(RequestInfo requestInfo, String tenantId, String hierarchyType) { + + // Create Boundary hierarchy search uri + String uri = getBoundaryHierarchySearchUri(); + + // Create request body + BoundaryTypeHierarchySearchCriteria searchCriteria = BoundaryTypeHierarchySearchCriteria.builder().tenantId(tenantId).hierarchyType(hierarchyType).build(); + BoundaryTypeHierarchySearchRequest searchRequest = BoundaryTypeHierarchySearchRequest.builder().requestInfo(requestInfo).boundaryTypeHierarchySearchCriteria(searchCriteria).build(); + BoundaryTypeHierarchyResponse searchResponse = new BoundaryTypeHierarchyResponse(); + + try { + searchResponse = restTemplate.postForObject(uri, searchRequest, BoundaryTypeHierarchyResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_BOUNDARY_HIERARCHY_DETAILS, e); + } + + return searchResponse; + } + + private String getBoundaryHierarchySearchUri() { + StringBuilder uri = new StringBuilder(); + uri.append(configs.getBoundaryServiceHost()).append(configs.getBoundaryHierarchySearchEndpoint()); + return uri.toString(); + } +} diff --git a/health-services/census-service/src/main/java/digit/util/BusinessServiceUtil.java b/health-services/census-service/src/main/java/digit/util/BusinessServiceUtil.java new file mode 100644 index 00000000000..ce127d4c637 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/util/BusinessServiceUtil.java @@ -0,0 +1,81 @@ +package digit.util; + +import digit.config.Configuration; +import digit.models.coremodels.RequestInfoWrapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.workflow.BusinessService; +import org.egov.common.contract.workflow.BusinessServiceResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.web.client.RestTemplate; + +import java.util.HashMap; +import java.util.Map; + +import static digit.config.ServiceConstants.*; + +@Slf4j +@Component +public class BusinessServiceUtil { + + private RestTemplate restTemplate; + + private Configuration config; + + public BusinessServiceUtil(RestTemplate restTemplate, Configuration configs) { + this.restTemplate = restTemplate; + this.config = configs; + } + + /** + * This method fetches business service details for the given tenant id and business service. + * + * @param requestInfo the request info from request. + * @param businessService businessService whose details are to be searched. + * @param tenantId tenantId from request. + * @return returns the business service response for the given tenant id and business service. + */ + public BusinessService fetchBusinessService(RequestInfo requestInfo, String businessService, String tenantId) { + + // Get business service uri + Map uriParameters = new HashMap<>(); + String uri = getBusinessServiceUri(businessService, tenantId, uriParameters); + + // Create request body + RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(requestInfo).build(); + BusinessServiceResponse businessServiceResponse = new BusinessServiceResponse(); + + try { + businessServiceResponse = restTemplate.postForObject(uri, requestInfoWrapper, BusinessServiceResponse.class, uriParameters); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_BUSINESS_SERVICE_DETAILS, e); + } + + if (CollectionUtils.isEmpty(businessServiceResponse.getBusinessServices())) { + throw new CustomException(NO_BUSINESS_SERVICE_DATA_FOUND_CODE, NO_BUSINESS_SERVICE_DATA_FOUND_MESSAGE); + } + + return businessServiceResponse.getBusinessServices().get(0); + } + + /** + * This method creates business service uri with query parameters + * + * @param businessService businessService whose details are to be searched. + * @param tenantId tenant id from the request. + * @param uriParameters map that stores values corresponding to the placeholder in uri + * @return + */ + private String getBusinessServiceUri(String businessService, String tenantId, Map uriParameters) { + + StringBuilder uri = new StringBuilder(); + uri.append(config.getWfHost()).append(config.getBusinessServiceSearchEndpoint()).append("?tenantId={tenantId}&businessServices={businessService}"); + + uriParameters.put("tenantId", tenantId); + uriParameters.put("businessService", businessService); + + return uri.toString(); + } +} diff --git a/health-services/census-service/src/main/java/digit/util/CommonUtil.java b/health-services/census-service/src/main/java/digit/util/CommonUtil.java new file mode 100644 index 00000000000..bf473f57cac --- /dev/null +++ b/health-services/census-service/src/main/java/digit/util/CommonUtil.java @@ -0,0 +1,151 @@ +package digit.util; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.NullNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import digit.web.models.CensusSearchCriteria; +import digit.web.models.CensusSearchRequest; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.workflow.BusinessService; +import org.egov.common.contract.workflow.State; +import org.egov.tracer.model.CustomException; +import org.postgresql.util.PGobject; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.sql.SQLException; +import java.util.*; + +import static digit.config.ServiceConstants.*; + +@Slf4j +@Component +public class CommonUtil { + + private ObjectMapper objectMapper; + + private BusinessServiceUtil businessServiceUtil; + + public CommonUtil(ObjectMapper objectMapper, BusinessServiceUtil businessServiceUtil) { + this.objectMapper = objectMapper; + this.businessServiceUtil = businessServiceUtil; + } + + /** + * Adds or updates the value of provided field in the additional details object. + * @param additionalDetails + * @param fieldToUpdate + * @param updatedValue + * @return + */ + public Map updateFieldInAdditionalDetails(Object additionalDetails, String fieldToUpdate, String updatedValue) { + try { + + // Get or create the additionalDetails as an ObjectNode + ObjectNode objectNode = additionalDetails instanceof NullNode + ? objectMapper.createObjectNode() + : objectMapper.convertValue(additionalDetails, ObjectNode.class); + + // Update or Add the field in additional details object + objectNode.put(fieldToUpdate, updatedValue); + + // Convert updated ObjectNode back to a Map and set it in 'additionalDetails' + Map updatedDetails = objectMapper.convertValue(objectNode, Map.class); + return updatedDetails; + + } catch (Exception e) { + throw new CustomException(ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_CODE, ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_MESSAGE); + } + } + + public Map updateFieldInAdditionalDetails(Object additionalDetails, Map fieldsToBeUpdated) { + try { + + // Get or create the additionalDetails as an ObjectNode + ObjectNode objectNode = (additionalDetails == null || additionalDetails instanceof NullNode) + ? objectMapper.createObjectNode() + : objectMapper.convertValue(additionalDetails, ObjectNode.class); + + // Update or add the field in additional details object + fieldsToBeUpdated.forEach((key, value) -> objectNode.set(key, objectMapper.valueToTree(value))); + + // Convert updated ObjectNode back to a Map + return objectMapper.convertValue(objectNode, Map.class); + + } catch (Exception e) { + throw new CustomException(ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_CODE, ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_MESSAGE + e); + } + } + + /** + * Removes the field to be removed from the additional details object. + * @param additionalDetails + * @param fieldToBeRemoved + * @return + */ + public Map removeFieldFromAdditionalDetails(Object additionalDetails, String fieldToBeRemoved) { + Map additionalDetailsMap = objectMapper.convertValue(additionalDetails, Map.class); + additionalDetailsMap.remove(fieldToBeRemoved); + + return additionalDetailsMap; + } + + /** + * Creates the census search request for the provided details. + * @param tenantId + * @param planConfigId + * @param serviceBoundary + * @return + */ + public CensusSearchRequest getCensusSearchRequest(String tenantId, String planConfigId, String serviceBoundary, List initiallySetServiceBoundaries, RequestInfo requestInfo) { + Set areaCodesForSearch = new HashSet<>(); + + areaCodesForSearch.addAll(Arrays.asList(serviceBoundary.split(","))); + areaCodesForSearch.addAll(initiallySetServiceBoundaries); + + CensusSearchCriteria searchCriteria = CensusSearchCriteria.builder() + .tenantId(tenantId) + .source(planConfigId) + .areaCodes(areaCodesForSearch.stream().toList()) + .offset(0) + .limit(areaCodesForSearch.size()) + .build(); + + return CensusSearchRequest.builder().requestInfo(requestInfo).censusSearchCriteria(searchCriteria).build(); + } + + /** + * Creates a list of all the workflow states for the provided business service. + * @param requestInfo + * @param businessService + * @param tenantId + * @return + */ + public List getStatusFromBusinessService(RequestInfo requestInfo, String businessService, String tenantId) { + BusinessService businessServices = businessServiceUtil.fetchBusinessService(requestInfo, businessService, tenantId); + + return businessServices.getStates().stream() + .map(State::getState) + .filter(state -> !ObjectUtils.isEmpty(state)) + .toList(); + } + + public PGobject convertToPgObject(Object additionalDetails) { + PGobject pGobject = new PGobject(); + + try { + String json = objectMapper.writeValueAsString(additionalDetails); + + pGobject.setType("jsonb"); + pGobject.setValue(json); + } catch (JsonProcessingException e) { + log.error("Error while processing JSON object to string", e); + } catch (SQLException e) { + log.error("Error while setting JSONB object", e); + } + + return pGobject; + } +} diff --git a/health-services/census-service/src/main/java/digit/util/PlanEmployeeAssignmnetUtil.java b/health-services/census-service/src/main/java/digit/util/PlanEmployeeAssignmnetUtil.java new file mode 100644 index 00000000000..0cb18bdb6db --- /dev/null +++ b/health-services/census-service/src/main/java/digit/util/PlanEmployeeAssignmnetUtil.java @@ -0,0 +1,59 @@ +package digit.util; + +import digit.config.Configuration; +import digit.web.models.plan.PlanEmployeeAssignmentResponse; +import digit.web.models.plan.PlanEmployeeAssignmentSearchCriteria; +import digit.web.models.plan.PlanEmployeeAssignmentSearchRequest; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.util.List; + +import static digit.config.ServiceConstants.ERROR_WHILE_FETCHING_EMPLOYEE_ASSIGNMENT_DETAILS; + +@Slf4j +@Component +public class PlanEmployeeAssignmnetUtil { + + private RestTemplate restTemplate; + + private Configuration config; + + public PlanEmployeeAssignmnetUtil(RestTemplate restTemplate, Configuration configs) { + this.restTemplate = restTemplate; + this.config = configs; + } + + /** + * This method fetches plan employee assignment from plan service for provided employeeID. + * @param planEmployeeAssignmentSearchRequest request containint the planEmployeeAssignment search criteria + * @return returns planEmployeeAssignment for provided search criteria. + */ + public PlanEmployeeAssignmentResponse fetchPlanEmployeeAssignment(PlanEmployeeAssignmentSearchRequest planEmployeeAssignmentSearchRequest) { + + // Get plan employee assignment uri + StringBuilder uri = getPlanEmployeeAssignmentUri(); + + PlanEmployeeAssignmentResponse response = new PlanEmployeeAssignmentResponse(); + + try { + response = restTemplate.postForObject(uri.toString(), planEmployeeAssignmentSearchRequest, PlanEmployeeAssignmentResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_EMPLOYEE_ASSIGNMENT_DETAILS, e); + } + + return response; + } + + /** + * This method creates the uri for plan employee assignment search + * + * @return uri for plan employee assignment search + */ + private StringBuilder getPlanEmployeeAssignmentUri() { + StringBuilder uri = new StringBuilder(); + return uri.append(config.getPlanServiceHost()).append(config.getPlanEmployeeAssignmentSearchEndpoint()); + } +} diff --git a/health-services/census-service/src/main/java/digit/util/QueryUtil.java b/health-services/census-service/src/main/java/digit/util/QueryUtil.java new file mode 100644 index 00000000000..3d9354df7a3 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/util/QueryUtil.java @@ -0,0 +1,139 @@ +package digit.util; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.config.Configuration; +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.model.CustomException; +import org.postgresql.util.PGobject; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.io.IOException; +import java.util.List; +import java.util.Set; +import java.util.stream.IntStream; + +import static digit.config.ServiceConstants.*; + +@Slf4j +@Component +public class QueryUtil { + + private Configuration config; + + private ObjectMapper objectMapper; + + private QueryUtil(Configuration config, ObjectMapper objectMapper) { + this.config = config; + this.objectMapper = objectMapper; + } + + /** + * This method adds "WHERE" clause and "AND" condition depending on preparedStatementList i.e., + * if preparedStatementList is empty, it will understand that it is the first clause being added so it + * will add "WHERE" to the query and otherwise it will + * + * @param query query to which Clause is to be added. + * @param preparedStmtList prepared statement list to check which clause to add. + */ + public void addClauseIfRequired(StringBuilder query, List preparedStmtList) { + if (preparedStmtList.isEmpty()) { + query.append(" WHERE "); + } else { + query.append(" AND "); + } + } + + /** + * This method returns a string with placeholders equal to the number of values that need to be put inside + * "IN" clause + * + * @param size number of placeholders to be added. + * @return a string with provided number of placeholders. + */ + public String createQuery(Integer size) { + StringBuilder builder = new StringBuilder(); + + IntStream.range(0, size).forEach(i -> { + builder.append(" ?"); + if (i != size - 1) + builder.append(","); + }); + + return builder.toString(); + } + + /** + * This method adds a set of String values into preparedStatementList. + * + * @param preparedStmtList prepared statement list to add Ids. + * @param ids set of Ids to be added. + */ + public void addToPreparedStatement(List preparedStmtList, Set ids) { + ids.forEach(id -> { + preparedStmtList.add(id); + }); + } + + public void addToPreparedStatement(List preparedStmtList, List ids) { + ids.forEach(id -> { + preparedStmtList.add(id); + }); + } + + /** + * This method appends order by clause to the query. + * + * @param query the query to which orderBy clause is to be added. + * @param orderByClause the orderBy clause to be added. + * @return a query with orderBy clause. + */ + public String addOrderByClause(String query, String orderByClause) { + return query + orderByClause; + } + + /** + * This method appends pagination i.e. limit and offset to the query. + * + * @param query the query to which pagination is to be added. + * @param preparedStmtList prepared statement list to add limit and offset. + * @return a query with pagination + */ + public String getPaginatedQuery(String query, List preparedStmtList) { + StringBuilder paginatedQuery = new StringBuilder(query); + + // Append offset + paginatedQuery.append(" OFFSET ? "); + preparedStmtList.add(config.getDefaultOffset()); + + // Append limit + paginatedQuery.append(" LIMIT ? "); + preparedStmtList.add(config.getDefaultLimit()); + + return paginatedQuery.toString(); + } + + /** + * This method is used to extract and parse JSON data into a JsonNode object. + * + * @param pgObject postgreSQL specific object. + * @return returns a JsonNode. + */ + public JsonNode parseJson(PGobject pgObject) { + + try { + if (!ObjectUtils.isEmpty(pgObject)) { + return objectMapper.readTree(pgObject.getValue()); + } + } catch (IOException e) { + log.error("Error parsing PGobject value: " + pgObject, e); + throw new CustomException(PARSING_ERROR_CODE, PARSING_ERROR_MESSAGE); + } + + // Return empty JsonNode if pgObject is empty + return objectMapper.createObjectNode(); + } + + +} diff --git a/health-services/census-service/src/main/java/digit/util/ResponseInfoFactory.java b/health-services/census-service/src/main/java/digit/util/ResponseInfoFactory.java new file mode 100644 index 00000000000..a10e7f50841 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/util/ResponseInfoFactory.java @@ -0,0 +1,27 @@ +package digit.util; + +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.stereotype.Component; + +import static digit.config.ServiceConstants.*; + +@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 msgId = requestInfo != null ? requestInfo.getMsgId() : ""; + final String responseStatus = success ? SUCCESSFUL : FAILED; + + return ResponseInfo.builder().apiId(apiId).ver(ver).ts(ts).resMsgId(RES_MSG_ID).msgId(msgId).resMsgId(RES_MSG_ID) + .status(responseStatus).build(); + } + +} \ No newline at end of file diff --git a/health-services/census-service/src/main/java/digit/web/controllers/CensusController.java b/health-services/census-service/src/main/java/digit/web/controllers/CensusController.java new file mode 100644 index 00000000000..8feabf4b455 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/controllers/CensusController.java @@ -0,0 +1,76 @@ +package digit.web.controllers; + +import digit.service.CensusService; +import digit.web.models.BulkCensusRequest; +import digit.web.models.CensusRequest; +import digit.web.models.CensusResponse; +import digit.web.models.CensusSearchRequest; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + + +@Controller +public class CensusController { + + private CensusService censusService; + + public CensusController(CensusService censusService) { + this.censusService = censusService; + } + + /** + * Request handler for serving census create requests + * + * @param body + * @return + */ + @RequestMapping(value = "/_create", method = RequestMethod.POST) + public ResponseEntity create(@Parameter(in = ParameterIn.DEFAULT, description = "", schema = @Schema()) @Valid @RequestBody CensusRequest body) { + CensusResponse response = censusService.create(body); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } + + /** + * Request handler for serving census search requests + * + * @param body + * @return + */ + @RequestMapping(value = "/_search", method = RequestMethod.POST) + public ResponseEntity search(@Parameter(in = ParameterIn.DEFAULT, description = "", schema = @Schema()) @Valid @RequestBody CensusSearchRequest body) { + CensusResponse response = censusService.search(body); + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + /** + * Request handler for serving census update requests + * + * @param body + * @return + */ + @RequestMapping(value = "/_update", method = RequestMethod.POST) + public ResponseEntity update(@Parameter(in = ParameterIn.DEFAULT, description = "", schema = @Schema()) @Valid @RequestBody CensusRequest body) { + CensusResponse response = censusService.update(body); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } + + /** + * Request handler for serving bulk census update requests + * + * @param body + * @return + */ + @RequestMapping(value = "/bulk/_update", method = RequestMethod.POST) + public ResponseEntity bulkUpdate(@Parameter(in = ParameterIn.DEFAULT, description = "", schema = @Schema()) @Valid @RequestBody BulkCensusRequest body) { + CensusResponse response = censusService.bulkUpdate(body); + return ResponseEntity.status(HttpStatus.CREATED).body(response); + } +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Assumption.java b/health-services/census-service/src/main/java/digit/web/models/AdditionalField.java similarity index 52% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Assumption.java rename to health-services/census-service/src/main/java/digit/web/models/AdditionalField.java index b8ed98d54e8..10351283cdb 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Assumption.java +++ b/health-services/census-service/src/main/java/digit/web/models/AdditionalField.java @@ -1,8 +1,9 @@ -package org.egov.processor.web.models; +package digit.web.models; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.Valid; -import jakarta.validation.constraints.*; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -12,34 +13,36 @@ import java.math.BigDecimal; /** - * Assumption + * AdditionalField */ @Validated @Data @AllArgsConstructor @NoArgsConstructor @Builder -public class Assumption { +public class AdditionalField { + @JsonProperty("id") @Valid @Size(min = 2, max = 64) private String id = null; @JsonProperty("key") + @Valid @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") + @NotNull private BigDecimal value = null; - @JsonProperty("active") - @NotNull - private Boolean active = true; + @JsonProperty("showOnUi") + private Boolean showOnUi = Boolean.TRUE; + + @JsonProperty("editable") + private Boolean editable = Boolean.TRUE; + @JsonProperty("order") + private Integer order = null; } diff --git a/health-services/census-service/src/main/java/digit/web/models/BulkCensusRequest.java b/health-services/census-service/src/main/java/digit/web/models/BulkCensusRequest.java new file mode 100644 index 00000000000..e88178822bb --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/BulkCensusRequest.java @@ -0,0 +1,33 @@ +package digit.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; + +import java.util.List; + +/** + * BulkCensusRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BulkCensusRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Census") + @Valid + private List census = null; + + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/Census.java b/health-services/census-service/src/main/java/digit/web/models/Census.java new file mode 100644 index 00000000000..55ed850ff18 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/Census.java @@ -0,0 +1,142 @@ +package digit.web.models; + + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +import java.util.List; +import java.util.Map; + +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.models.AuditDetails; +import org.egov.common.contract.models.Workflow; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; + + +/** + * Census + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Census { + + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("tenantId") + @NotNull + private String tenantId = null; + + @JsonProperty("hierarchyType") + @NotNull + private String hierarchyType = null; + + @JsonProperty("boundaryCode") + @NotNull + private String boundaryCode = null; + + @JsonProperty("assignee") + private List assignee = null; + + @JsonProperty("status") + @Size(max = 64) + private String status = null; + + @JsonProperty("type") + @NotNull + private TypeEnum type = null; + + @JsonProperty("totalPopulation") + @NotNull + private Long totalPopulation = null; + + @JsonProperty("populationByDemographics") + @Valid + private List populationByDemographics = null; + + @JsonProperty("additionalFields") + @Valid + private List additionalFields = null; + + @JsonProperty("effectiveFrom") + private Long effectiveFrom = null; + + @JsonProperty("effectiveTo") + private Long effectiveTo = null; + + @JsonProperty("source") + @NotNull + private String source = null; + + @JsonIgnore + private List boundaryAncestralPath = null; + + @JsonIgnore + @Builder.Default + private Boolean partnerAssignmentValidationEnabled = Boolean.TRUE; + + @JsonProperty("facilityAssigned") + private Boolean facilityAssigned = null; + + @JsonProperty("workflow") + @Valid + private Workflow workflow; + + @JsonIgnore + private List assigneeJurisdiction; + + @JsonProperty("jurisdictionMapping") + private Map jurisdictionMapping; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("auditDetails") + private @Valid AuditDetails auditDetails; + + /** + * Gets or Sets type + */ + public enum TypeEnum { + PEOPLE("people"), + ANIMALS("animals"), + PLANTS("plants"), + OTHER("other"); + + private String value; + + TypeEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static TypeEnum fromValue(String text) { + for (TypeEnum b : TypeEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/CensusDTO.java b/health-services/census-service/src/main/java/digit/web/models/CensusDTO.java new file mode 100644 index 00000000000..02d3c7d1b2b --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/CensusDTO.java @@ -0,0 +1,104 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; +import java.util.Map; + +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.models.AuditDetails; +import org.egov.common.contract.models.Workflow; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; + + +/** + * CensusDTO + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusDTO { + + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("tenantId") + @NotNull + private String tenantId = null; + + @JsonProperty("hierarchyType") + @NotNull + private String hierarchyType = null; + + @JsonProperty("boundaryCode") + @NotNull + private String boundaryCode = null; + + @JsonProperty("assignee") + private String assignee = null; + + @JsonProperty("status") + private String status = null; + + @JsonProperty("type") + @NotNull + private String type = null; + + @JsonProperty("totalPopulation") + @NotNull + private Long totalPopulation = null; + + @JsonProperty("populationByDemographics") + @Valid + private List populationByDemographics = null; + + @JsonProperty("additionalFields") + @Valid + private List additionalFields = null; + + @JsonProperty("effectiveFrom") + private Long effectiveFrom = null; + + @JsonProperty("effectiveTo") + private Long effectiveTo = null; + + @JsonProperty("source") + @NotNull + private String source = null; + + @JsonProperty("boundaryAncestralPath") + private String boundaryAncestralPath = null; + + @JsonIgnore + private boolean partnerAssignmentValidationEnabled; + + @JsonProperty("facilityAssigned") + private Boolean facilityAssigned = null; + + @JsonProperty("workflow") + @Valid + private Workflow workflow; + + @JsonIgnore + private List assigneeJurisdiction; + + @JsonProperty("jurisdictionMapping") + private Map jurisdictionMapping; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("auditDetails") + private @Valid AuditDetails auditDetails; +} diff --git a/health-services/census-service/src/main/java/digit/web/models/CensusRequest.java b/health-services/census-service/src/main/java/digit/web/models/CensusRequest.java new file mode 100644 index 00000000000..d8755bbbda9 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/CensusRequest.java @@ -0,0 +1,31 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * CensusRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Census") + @Valid + private Census census = null; + + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/CensusRequestDTO.java b/health-services/census-service/src/main/java/digit/web/models/CensusRequestDTO.java new file mode 100644 index 00000000000..7b1ced9a7db --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/CensusRequestDTO.java @@ -0,0 +1,31 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * CensusRequestDTO + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusRequestDTO { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Census") + @Valid + private CensusDTO censusDTO = null; + + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/CensusResponse.java b/health-services/census-service/src/main/java/digit/web/models/CensusResponse.java new file mode 100644 index 00000000000..4aace9435f2 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/CensusResponse.java @@ -0,0 +1,42 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; +import java.util.Map; + +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * CensusResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Census") + @Valid + private List census = null; + + @JsonProperty("TotalCount") + @Valid + private Integer totalCount = null; + + @JsonProperty("StatusCount") + @Valid + private Map statusCount = null; + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/CensusSearchCriteria.java b/health-services/census-service/src/main/java/digit/web/models/CensusSearchCriteria.java new file mode 100644 index 00000000000..363da1907ae --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/CensusSearchCriteria.java @@ -0,0 +1,72 @@ +package digit.web.models; + + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.springframework.validation.annotation.Validated; +import jakarta.validation.constraints.*; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * CensusSearchCriteria + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusSearchCriteria { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("ids") + private Set ids = null; + + @JsonProperty("tenantId") + @Size(min = 1, max = 100) + private String tenantId = null; + + @JsonProperty("areaCodes") + private List areaCodes = null; + + @JsonProperty("status") + private String status = null; + + @JsonProperty("assignee") + private String assignee = null; + + @JsonProperty("source") + private String source = null; + + @JsonProperty("facilityAssigned") + private Boolean facilityAssigned = null; + + @JsonProperty("jurisdiction") + private List jurisdiction = null; + + @JsonProperty("effectiveTo") + private Long effectiveTo = null; + + @JsonProperty("limit") + private Integer limit = null; + + @JsonProperty("offset") + private Integer offset = null; + + public CensusSearchCriteria addAreaCodesItem(String areaCodesItem) { + if (this.areaCodes == null) { + this.areaCodes = new ArrayList<>(); + } + this.areaCodes.add(areaCodesItem); + return this; + } + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/CensusSearchRequest.java b/health-services/census-service/src/main/java/digit/web/models/CensusSearchRequest.java new file mode 100644 index 00000000000..ac595972fe7 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/CensusSearchRequest.java @@ -0,0 +1,33 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * CensusSearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusSearchRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("CensusSearchCriteria") + @Valid + @NotNull + private CensusSearchCriteria censusSearchCriteria = null; + + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/PopulationByDemographic.java b/health-services/census-service/src/main/java/digit/web/models/PopulationByDemographic.java new file mode 100644 index 00000000000..8b984e06d89 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/PopulationByDemographic.java @@ -0,0 +1,69 @@ +package digit.web.models; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import jakarta.validation.constraints.Size; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * PopulationByDemographic + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PopulationByDemographic { + + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("demographicVariable") + private DemographicVariableEnum demographicVariable = null; + + @JsonProperty("populationDistribution") + private Object populationDistribution = null; + + /** + * Gets or Sets demographicVariable + */ + public enum DemographicVariableEnum { + AGE("age"), + + GENDER("gender"), + + ETHNICITY("ethnicity"); + + private String value; + + DemographicVariableEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static DemographicVariableEnum fromValue(String text) { + for (DemographicVariableEnum b : DemographicVariableEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/RequestInfoWrapper.java b/health-services/census-service/src/main/java/digit/web/models/RequestInfoWrapper.java new file mode 100644 index 00000000000..b36665e3e25 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/RequestInfoWrapper.java @@ -0,0 +1,18 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; +import org.egov.common.contract.request.RequestInfo; + + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class RequestInfoWrapper { + + @JsonProperty("RequestInfo") + private RequestInfo requestInfo; + +} \ No newline at end of file diff --git a/health-services/census-service/src/main/java/digit/web/models/boundary/BoundarySearchResponse.java b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundarySearchResponse.java new file mode 100644 index 00000000000..7f92e1f53c8 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundarySearchResponse.java @@ -0,0 +1,42 @@ +package digit.web.models.boundary; + +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; + +/** + * 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/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchy.java b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchy.java new file mode 100644 index 00000000000..45ab5a19141 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchy.java @@ -0,0 +1,30 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryTypeHierarchy + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchy { + + @JsonProperty("boundaryType") + private String boundaryType = null; + + @JsonProperty("parentBoundaryType") + private String parentBoundaryType = null; + + @JsonProperty("active") + private Boolean active = null; + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyDefinition.java b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyDefinition.java new file mode 100644 index 00000000000..6faf8ac0b49 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyDefinition.java @@ -0,0 +1,45 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import jakarta.validation.Valid; +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; + +import java.util.List; + +/** + * BoundaryTypeHierarchyDefinition + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchyDefinition { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("hierarchyType") + private String hierarchyType = null; + + @JsonProperty("boundaryHierarchy") + @Valid + private List boundaryHierarchy = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("boundaryHierarchyJsonNode") + private JsonNode boundaryHierarchyJsonNode = null; + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyResponse.java b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyResponse.java new file mode 100644 index 00000000000..6372620c43c --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyResponse.java @@ -0,0 +1,36 @@ +package digit.web.models.boundary; + +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.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * BoundaryTypeHierarchyResponse + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchyResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("totalCount") + private Integer totalCount = null; + + @JsonProperty("BoundaryHierarchy") + @Valid + private List boundaryHierarchy = null; + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchCriteria.java b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchCriteria.java new file mode 100644 index 00000000000..7ad5be0790f --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchCriteria.java @@ -0,0 +1,38 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.constraints.*; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * BoundaryTypeHierarchySearchCriteria + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchySearchCriteria { + + @JsonProperty("tenantId") + @Size(min = 1, max = 100) + @NotNull + private String tenantId = null; + + @JsonProperty("hierarchyType") + @Size(min = 1, max = 100) + private String hierarchyType = null; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} + diff --git a/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchRequest.java b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchRequest.java new file mode 100644 index 00000000000..b85ffffd857 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchRequest.java @@ -0,0 +1,33 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +import jakarta.validation.Valid; + +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * BoundaryTypeHierarchySearchRequest + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchySearchRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("BoundaryTypeHierarchySearchCriteria") + @Valid + private BoundaryTypeHierarchySearchCriteria boundaryTypeHierarchySearchCriteria = null; + +} diff --git a/health-services/census-service/src/main/java/digit/web/models/boundary/EnrichedBoundary.java b/health-services/census-service/src/main/java/digit/web/models/boundary/EnrichedBoundary.java new file mode 100644 index 00000000000..c42af3737ce --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/boundary/EnrichedBoundary.java @@ -0,0 +1,42 @@ +package digit.web.models.boundary; + +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; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 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/census-service/src/main/java/digit/web/models/boundary/HierarchyRelation.java b/health-services/census-service/src/main/java/digit/web/models/boundary/HierarchyRelation.java new file mode 100644 index 00000000000..7a3e26f6595 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/boundary/HierarchyRelation.java @@ -0,0 +1,34 @@ +package digit.web.models.boundary; + +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 java.util.List; + +/** + * 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/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignment.java b/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignment.java new file mode 100644 index 00000000000..1cec6f46300 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignment.java @@ -0,0 +1,63 @@ +package digit.web.models.plan; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +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.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * PlanEmployeeAssignment + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignment { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("planConfigurationId") + @NotNull + @Size(min = 2, max = 64) + private String planConfigurationId = null; + + @JsonProperty("employeeId") + @NotNull + @Size(min = 2, max = 64) + private String employeeId = null; + + @JsonProperty("role") + @NotNull + @Size(min = 2, max = 64) + private String role = null; + + @JsonProperty("jurisdiction") + @Valid + @NotEmpty + private List jurisdiction = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("active") + private Boolean active = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; +} diff --git a/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentResponse.java b/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentResponse.java new file mode 100644 index 00000000000..8e6e0260116 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentResponse.java @@ -0,0 +1,37 @@ +package digit.web.models.plan; + +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.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + + +/** + * PlanEmployeeAssignmentResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignmentResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("PlanEmployeeAssignment") + @Valid + private List planEmployeeAssignment = null; + + @JsonProperty("TotalCount") + @Valid + private Integer totalCount = null; +} + diff --git a/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentSearchCriteria.java b/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentSearchCriteria.java new file mode 100644 index 00000000000..6e38c1dad95 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentSearchCriteria.java @@ -0,0 +1,50 @@ +package digit.web.models.plan; + +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.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * PlanEmployeeAssignmentSearchCriteria + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignmentSearchCriteria { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @Size(min = 2, max = 100) + @NotNull + private String tenantId = null; + + @JsonProperty("employeeId") + private List employeeId = null; + + @JsonProperty("planConfigurationId") + @Size(max = 64) + private String planConfigurationId = null; + + @JsonProperty("role") + @Size(min = 2, max = 64) + private List role = null; + + @JsonProperty("jurisdiction") + @Valid + private List jurisdiction = null; + + @JsonProperty("active") + private Boolean active = null; +} diff --git a/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentSearchRequest.java b/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentSearchRequest.java new file mode 100644 index 00000000000..4a343fb8e45 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/plan/PlanEmployeeAssignmentSearchRequest.java @@ -0,0 +1,29 @@ +package digit.web.models.plan; + +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; + +/** + * PlanEmployeeAssignmentSearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignmentSearchRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("PlanEmployeeAssignmentSearchCriteria") + @Valid + private PlanEmployeeAssignmentSearchCriteria planEmployeeAssignmentSearchCriteria = null; +} diff --git a/health-services/census-service/src/main/java/digit/web/models/plan/PlanFacilityDTO.java b/health-services/census-service/src/main/java/digit/web/models/plan/PlanFacilityDTO.java new file mode 100644 index 00000000000..ce15f091cec --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/plan/PlanFacilityDTO.java @@ -0,0 +1,72 @@ +package digit.web.models.plan; + +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.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * Plan Facility DTO + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanFacilityDTO { + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("planConfigurationId") + @NotNull + @Size(max = 64) + private String planConfigurationId = null; + + @JsonProperty("planConfigurationName") + private String planConfigurationName = null; + + @JsonProperty("facilityId") + @NotNull + @Size(max = 64) + private String facilityId = null; + + @JsonProperty("residingBoundary") + @NotNull + @Size(min = 1, max = 64) + private String residingBoundary = null; + + // Changed List to String to store as JSON + @JsonProperty("serviceBoundaries") + @NotNull + @Size(min = 1) + private String serviceBoundaries = null; // Store as JSON string + + @JsonProperty("initiallySetServiceBoundaries") + private List initiallySetServiceBoundaries; + + @JsonProperty("facilityName") + private String facilityName = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("active") + @NotNull + private Boolean active = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + +} \ No newline at end of file diff --git a/health-services/census-service/src/main/java/digit/web/models/plan/PlanFacilityRequestDTO.java b/health-services/census-service/src/main/java/digit/web/models/plan/PlanFacilityRequestDTO.java new file mode 100644 index 00000000000..6bae9ac51c2 --- /dev/null +++ b/health-services/census-service/src/main/java/digit/web/models/plan/PlanFacilityRequestDTO.java @@ -0,0 +1,33 @@ +package digit.web.models.plan; + +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.springframework.validation.annotation.Validated; + +/** + * PlanFacilityRequestDTO + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanFacilityRequestDTO { + + @JsonProperty("RequestInfo") + @Valid + @NotNull + private RequestInfo requestInfo; + + @JsonProperty("PlanFacility") + @Valid + @NotNull + private PlanFacilityDTO planFacilityDTO; + +} diff --git a/health-services/census-service/src/main/resources/application.properties b/health-services/census-service/src/main/resources/application.properties new file mode 100644 index 00000000000..fcf43df5960 --- /dev/null +++ b/health-services/census-service/src/main/resources/application.properties @@ -0,0 +1,82 @@ +server.contextPath=/census-service +server.servlet.context-path=/census-service +management.endpoints.web.base-path=/ +server.port=8080 +app.timezone=UTC + +#DATABASE CONFIGURATION +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/censusDB +spring.datasource.username=postgres +spring.datasource.password=postgres + +#FLYWAY CONFIGURATION +spring.flyway.url=jdbc:postgresql://localhost:5432/censusDB +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=census-serivce +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 +spring.kafka.producer.properties.max.request.size=3000000 + +# 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 + +#PERSISTER KAFKA TOPICS +census.create.topic=census-create-topic +census.update.topic=census-update-topic +census.bulk.update.topic=census-bulk-update-topic + +egov.sms.notification.topic=egov.core.notification.sms +kafka.topics.receipt.create=dss-collection + +#Boundary service urls +egov.boundary.service.host=https://unified-dev.digit.org +egov.boundary.relationship.search.endpoint=/boundary-service/boundary-relationships/_search +egov.boundary.hierarchy.search.endpoint=/boundary-service/boundary-hierarchy-definition/_search + +#Plan service urls +egov.plan.service.host=https://unified-dev.digit.org +egov.plan.employee.assignment.search.endpoint=/plan-service/employee/_search + +# Workflow +egov.workflow.host=https://unified-dev.digit.org +egov.workflow.transition.path=/egov-workflow-v2/egov-wf/process/_transition +egov.business.service.search.endpoint=/egov-workflow-v2/egov-wf/businessservice/_search +workflow.initiate.action=INITIATE +workflow.intermediate.action=EDIT_AND_SEND_FOR_APPROVAL,APPROVE +workflow.send.back.actions=SEND_BACK_FOR_CORRECTION + + +#Pagination config +census.default.offset=0 +census.default.limit=10 + +resource.config.consumer.census.create.topic=resource-census-create-topic +resource.config.consumer.census.update.topic=resource-census-update-topic + +plan.facility.update.topic=update-plan-facility + +#Roles for census +allowed.census.roles={'POPULATION_DATA_APPROVER','ROOT_POPULATION_DATA_APPROVER'} +workflow.restricted.roles={'ROOT_FACILITY_CATCHMENT_MAPPER','FACILITY_CATCHMENT_MAPPER'} \ No newline at end of file diff --git a/health-services/census-service/src/main/resources/db/Dockerfile b/health-services/census-service/src/main/resources/db/Dockerfile new file mode 100644 index 00000000000..f38638a269f --- /dev/null +++ b/health-services/census-service/src/main/resources/db/Dockerfile @@ -0,0 +1,9 @@ +FROM egovio/flyway:10.7.1 + +COPY ./migration/main /flyway/sql + +COPY migrate.sh /usr/bin/migrate.sh + +RUN chmod +x /usr/bin/migrate.sh + +ENTRYPOINT ["/usr/bin/migrate.sh"] diff --git a/health-services/resource-estimation-service/src/main/resources/db/migrate.sh b/health-services/census-service/src/main/resources/db/migrate.sh similarity index 67% rename from health-services/resource-estimation-service/src/main/resources/db/migrate.sh rename to health-services/census-service/src/main/resources/db/migrate.sh index 43960b25cdb..c58d6f91e3f 100644 --- a/health-services/resource-estimation-service/src/main/resources/db/migrate.sh +++ b/health-services/census-service/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/census-service/src/main/resources/db/migration/main/V20240925155908__census_create_ddl.sql b/health-services/census-service/src/main/resources/db/migration/main/V20240925155908__census_create_ddl.sql new file mode 100644 index 00000000000..cf80c461292 --- /dev/null +++ b/health-services/census-service/src/main/resources/db/migration/main/V20240925155908__census_create_ddl.sql @@ -0,0 +1,36 @@ +-- Table: census +CREATE TABLE census ( + id character varying(64) NOT NULL, + tenant_id character varying(64) NOT NULL, + hierarchy_type character varying(64) NOT NULL, + boundary_code character varying(64) NOT NULL, + type character varying(64) NOT NULL, + total_population bigint NOT NULL, + effective_from bigint NOT NULL, + effective_to bigint, + source character varying(255) NOT NULL, + status character varying(255), + assignee character varying(255), + facility_assigned boolean, + boundary_ancestral_path TEXT NOT NULL, + additional_details JSONB, + created_by character varying(64) NOT NULL, + created_time bigint NOT NULL, + last_modified_by character varying(64) NOT NULL, + last_modified_time bigint NOT NULL, + CONSTRAINT uk_census_id PRIMARY KEY (id) +); + +-- Table: population_by_demographics +CREATE TABLE population_by_demographics ( + id character varying(64), + census_id character varying(64), + demographic_variable character varying(64), + population_distribution JSONB, + created_by character varying(64), + created_time bigint, + last_modified_by character varying(64), + last_modified_time bigint, + CONSTRAINT uk_population_by_demographics_id PRIMARY KEY (id), + FOREIGN KEY (census_id) REFERENCES census(id) +); diff --git a/health-services/census-service/src/main/resources/db/migration/main/V20241105152700__census_additional_field_create_ddl.sql b/health-services/census-service/src/main/resources/db/migration/main/V20241105152700__census_additional_field_create_ddl.sql new file mode 100644 index 00000000000..9887f73656f --- /dev/null +++ b/health-services/census-service/src/main/resources/db/migration/main/V20241105152700__census_additional_field_create_ddl.sql @@ -0,0 +1,12 @@ +-- Table: additional_field +CREATE TABLE additional_field ( + id character varying(64) NOT NULL, + census_id character varying(64) NOT NULL, + "key" character varying(64) NOT NULL, + "value" numeric(12,2) NOT NULL, + show_on_ui boolean DEFAULT true NOT NULL, + editable boolean DEFAULT true NOT NULL, + "order" bigint NOT NULL, + CONSTRAINT uk_additional_field_id PRIMARY KEY (id), + FOREIGN KEY (census_id) REFERENCES census(id) +); diff --git a/health-services/census-service/src/main/resources/db/migration/main/V20241126120700__alter_census_assignee_create_ddl.sql b/health-services/census-service/src/main/resources/db/migration/main/V20241126120700__alter_census_assignee_create_ddl.sql new file mode 100644 index 00000000000..7d271361aae --- /dev/null +++ b/health-services/census-service/src/main/resources/db/migration/main/V20241126120700__alter_census_assignee_create_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE census ALTER COLUMN assignee TYPE TEXT; \ No newline at end of file diff --git a/health-services/census-service/src/main/resources/start.sh b/health-services/census-service/src/main/resources/start.sh new file mode 100644 index 00000000000..36eccc0ae97 --- /dev/null +++ b/health-services/census-service/src/main/resources/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/health-services/census-service/src/test/java/digit/TestConfiguration.java b/health-services/census-service/src/test/java/digit/TestConfiguration.java new file mode 100644 index 00000000000..570236cfc94 --- /dev/null +++ b/health-services/census-service/src/test/java/digit/TestConfiguration.java @@ -0,0 +1,16 @@ +package digit; + +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/census-service/src/test/java/digit/web/controllers/CensusControllerTest.java b/health-services/census-service/src/test/java/digit/web/controllers/CensusControllerTest.java new file mode 100644 index 00000000000..df3d8c23267 --- /dev/null +++ b/health-services/census-service/src/test/java/digit/web/controllers/CensusControllerTest.java @@ -0,0 +1,69 @@ +package digit.web.controllers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.service.CensusService; +import digit.web.models.CensusRequest; +import digit.web.models.CensusSearchRequest; +import org.junit.Test; +import org.junit.Ignore; +import org.junit.runner.RunWith; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import digit.TestConfiguration; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * API tests for CensusApiController + */ +@Ignore +@RunWith(SpringRunner.class) +@WebMvcTest(CensusController.class) +@Import(TestConfiguration.class) +public class CensusControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private JdbcTemplate jdbcTemplate; + + @MockBean + private CensusService service; + + @Autowired + private ObjectMapper objectMapper; + + + @Test + public void censusCreatePostSuccess() throws Exception { + CensusRequest request = CensusRequest.builder().build(); + mockMvc.perform(post("/_create").contentType(MediaType + .APPLICATION_JSON_UTF8).content(objectMapper.writeValueAsString(request))) + .andExpect(status().isAccepted()); + } + + @Test + public void censusSearchPostSuccess() throws Exception { + CensusSearchRequest request = CensusSearchRequest.builder().build(); + mockMvc.perform(post("/_search").contentType(MediaType + .APPLICATION_JSON_UTF8).content(objectMapper.writeValueAsString(request))) + .andExpect(status().isOk()); + } + + @Test + public void censusUpdatePostSuccess() throws Exception { + CensusRequest request = CensusRequest.builder().build(); + mockMvc.perform(post("/_update").contentType(MediaType + .APPLICATION_JSON_UTF8).content(objectMapper.writeValueAsString(request))) + .andExpect(status().isAccepted()); + } + +} diff --git a/health-services/facility/pom.xml b/health-services/facility/pom.xml index 1eb0038656a..b0a2d7d2cad 100644 --- a/health-services/facility/pom.xml +++ b/health-services/facility/pom.xml @@ -45,12 +45,12 @@ org.egov.common health-services-common - 1.0.17-SNAPSHOT + 1.0.20-SNAPSHOT org.egov.common health-services-models - 1.0.20-SNAPSHOT + 1.0.23-SNAPSHOT compile 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 482ac988b98..2d6b0fd9a6a 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 @@ -5,6 +5,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.models.core.SearchResponse; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilitySearch; import org.egov.common.producer.Producer; @@ -23,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 @@ -35,7 +37,7 @@ public FacilityRepository(Producer producer, NamedParameterJdbcTemplate namedPar facilityRowMapper, Optional.of("facility")); } - public List findById(List ids, String columnName, Boolean includeDeleted) { + public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { List objFound = findInCache(ids); if (!includeDeleted) { objFound = objFound.stream() @@ -48,7 +50,7 @@ public List findById(List ids, String columnName, Boolean incl .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) .collect(Collectors.toList())); if (ids.isEmpty()) { - return objFound; + return SearchResponse.builder().response(objFound).build(); } } @@ -61,10 +63,12 @@ public List findById(List ids, String columnName, Boolean incl objFound.addAll(this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper)); putInCache(objFound); - return objFound; + + /*The totalCount is being set automatically through the builder method.*/ + return SearchResponse.builder().response(objFound).build(); } - public List find(FacilitySearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { + public SearchResponse find(FacilitySearch 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 facility f LEFT JOIN address a ON f.addressid = a.id"; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); @@ -83,12 +87,17 @@ public List find(FacilitySearch searchObject, Integer limit, Integer o if (lastChangedSince != null) { query = query + "and lastModifiedTime>=:lastModifiedTime "; } - query = query + "ORDER BY f.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 + " LIMIT :limit OFFSET :offset"; paramsMap.put("limit", limit); paramsMap.put("offset", offset); - return this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + List facilities = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + + return SearchResponse.builder().response(facilities).totalCount(totalCount).build(); } } 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 3517293adcf..73276c91d88 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 @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.facility.Address; import org.egov.common.models.facility.AddressType; 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 769aae4b725..76ceb67033d 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,13 +1,16 @@ package org.egov.facility.service; +import io.micrometer.core.instrument.search.Search; 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; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilityBulkRequest; import org.egov.common.models.facility.FacilityRequest; import org.egov.common.models.facility.FacilitySearchRequest; +import org.egov.common.models.project.ProjectBeneficiary; import org.egov.common.validator.Validator; import org.egov.facility.config.FacilityConfiguration; import org.egov.facility.repository.FacilityRepository; @@ -173,23 +176,27 @@ public List delete(FacilityBulkRequest request, boolean isBulk) { return validEntities; } - public List search(FacilitySearchRequest facilitySearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { + public SearchResponse search(FacilitySearchRequest facilitySearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { log.info("starting search method for facility"); String idFieldName = getIdFieldName(facilitySearchRequest.getFacility()); if (isSearchByIdOnly(facilitySearchRequest.getFacility(), idFieldName)) { List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections .singletonList(facilitySearchRequest.getFacility())), facilitySearchRequest.getFacility()); - return facilityRepository.findById(ids, idFieldName, includeDeleted).stream() + SearchResponse searchResponse = facilityRepository.findById(ids, idFieldName, includeDeleted); + List facilities = searchResponse.getResponse().stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); + searchResponse.setResponse(facilities); + + return searchResponse; } log.info("completed search method for facility"); diff --git a/health-services/facility/src/main/java/org/egov/facility/validator/FNonExistentValidator.java b/health-services/facility/src/main/java/org/egov/facility/validator/FNonExistentValidator.java index c666d6b3264..2857a038490 100644 --- a/health-services/facility/src/main/java/org/egov/facility/validator/FNonExistentValidator.java +++ b/health-services/facility/src/main/java/org/egov/facility/validator/FNonExistentValidator.java @@ -50,7 +50,7 @@ public Map> validate(FacilityBulkRequest request) { Map eMap = getIdToObjMap(validEntities, idMethod); if (!eMap.isEmpty()) { List entityIds = new ArrayList<>(eMap.keySet()); - List existingEntities = facilityRepository.findById(entityIds, getIdFieldName(idMethod), false); + List existingEntities = facilityRepository.findById(entityIds, getIdFieldName(idMethod), false).getResponse(); List nonExistentEntities = checkNonExistentEntities(eMap, existingEntities, idMethod); nonExistentEntities.forEach(facility -> { diff --git a/health-services/facility/src/main/java/org/egov/facility/validator/FRowVersionValidator.java b/health-services/facility/src/main/java/org/egov/facility/validator/FRowVersionValidator.java index df76ac89fe4..17adda2b3f2 100644 --- a/health-services/facility/src/main/java/org/egov/facility/validator/FRowVersionValidator.java +++ b/health-services/facility/src/main/java/org/egov/facility/validator/FRowVersionValidator.java @@ -47,7 +47,7 @@ public Map> validate(FacilityBulkRequest request) { Map eMap = getIdToObjMap(validEntities, idMethod); if (!eMap.isEmpty()) { List entityIds = new ArrayList<>(eMap.keySet()); - List existingEntities = facilityRepository.findById(entityIds, getIdFieldName(idMethod), false); + List existingEntities = facilityRepository.findById(entityIds, getIdFieldName(idMethod), false).getResponse(); List entitiesWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(eMap, existingEntities, idMethod); entitiesWithMismatchedRowVersion.forEach(facility -> { 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 3ca37071ca8..67de20615b1 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 @@ -8,6 +8,7 @@ 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.facility.Facility; import org.egov.common.models.facility.FacilityBulkRequest; @@ -111,7 +112,7 @@ 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( + SearchResponse searchResponse = facilityService.search( request, urlParams.getLimit(), urlParams.getOffset(), @@ -119,7 +120,9 @@ public ResponseEntity facilityV1SearchPost( urlParams.getLastChangedSince(), urlParams.getIncludeDeleted()); FacilityBulkResponse response = FacilityBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).facilities(facilities).build(); + .createResponseInfo(request.getRequestInfo(), true)) + .facilities(searchResponse.getResponse()) + .totalCount(searchResponse.getTotalCount()).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/facility/src/test/java/org/egov/facility/validator/NonExistentEntityValidatorTest.java b/health-services/facility/src/test/java/org/egov/facility/validator/NonExistentEntityValidatorTest.java index a6e8c05f7c1..06955011bc0 100644 --- a/health-services/facility/src/test/java/org/egov/facility/validator/NonExistentEntityValidatorTest.java +++ b/health-services/facility/src/test/java/org/egov/facility/validator/NonExistentEntityValidatorTest.java @@ -1,8 +1,10 @@ package org.egov.facility.validator; import org.egov.common.models.Error; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilityBulkRequest; +import org.egov.common.models.household.Household; import org.egov.facility.helper.FacilityBulkRequestTestBuilder; import org.egov.facility.helper.FacilityTestBuilder; import org.egov.facility.repository.FacilityRepository; @@ -37,7 +39,7 @@ class NonExistentEntityValidatorTest { void shouldAddToErrorDetailsMapIfEntityNotFound() { FacilityBulkRequest request = FacilityBulkRequestTestBuilder.builder().withFacilityId("some-id").withRequestInfo().build(); when(facilityRepository.findById(anyList(), anyString(), anyBoolean())) - .thenReturn(Collections.emptyList()); + .thenReturn(SearchResponse.builder().build()); Map> errorDetailsMap = fNonExistentValidator.validate(request); @@ -49,7 +51,9 @@ void shouldAddToErrorDetailsMapIfEntityNotFound() { void shouldNotAddToErrorDetailsMapIfEntityFound() { FacilityBulkRequest request = FacilityBulkRequestTestBuilder.builder().withFacilityId("some-id").withRequestInfo().build(); when(facilityRepository.findById(anyList(), anyString(), anyBoolean())) - .thenReturn(Collections.singletonList(FacilityTestBuilder.builder().withFacility().withId("some-id").build())); + .thenReturn(SearchResponse.builder(). + response(Collections.singletonList(FacilityTestBuilder.builder().withFacility().withId("some-id").build())) + .build()); Map> errorDetailsMap = fNonExistentValidator.validate(request); diff --git a/health-services/facility/src/test/java/org/egov/facility/validator/RowVersionValidatorTest.java b/health-services/facility/src/test/java/org/egov/facility/validator/RowVersionValidatorTest.java index 1f44a89f94a..52f92421c49 100644 --- a/health-services/facility/src/test/java/org/egov/facility/validator/RowVersionValidatorTest.java +++ b/health-services/facility/src/test/java/org/egov/facility/validator/RowVersionValidatorTest.java @@ -1,6 +1,7 @@ package org.egov.facility.validator; import org.egov.common.models.Error; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilityBulkRequest; import org.egov.facility.helper.FacilityBulkRequestTestBuilder; @@ -39,7 +40,9 @@ void shouldAddToErrorDetailsIfRowVersionMismatchFound() { FacilityBulkRequest request = FacilityBulkRequestTestBuilder.builder().withFacilityId("some-id").withRequestInfo().build(); request.getFacilities().get(0).setRowVersion(2); when(facilityRepository.findById(anyList(), anyString(), anyBoolean())) - .thenReturn(Collections.singletonList(FacilityTestBuilder.builder().withFacility().withId("some-id").build())); + .thenReturn(SearchResponse.builder() + .response(Collections.singletonList(FacilityTestBuilder.builder().withFacility().withId("some-id").build())) + .build()); Map> errorDetailsMap = fRowVersionValidator.validate(request); @@ -51,7 +54,8 @@ void shouldAddToErrorDetailsIfRowVersionMismatchFound() { void shouldNotAddToErrorDetailsIfRowVersionSimilar() { FacilityBulkRequest request = FacilityBulkRequestTestBuilder.builder().withFacilityId("some-id").withRequestInfo().build(); when(facilityRepository.findById(anyList(), anyString(), anyBoolean())) - .thenReturn(Collections.singletonList(FacilityTestBuilder.builder().withFacility().withId("some-id").build())); + .thenReturn(SearchResponse.builder() + .response(Collections.singletonList(FacilityTestBuilder.builder().withFacility().withId("some-id").build())).build()); Map> errorDetailsMap = fRowVersionValidator.validate(request); 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 392df06c2e1..d99c514e51b 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/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index 703b5521652..8b9ef49d763 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 @@ -98,7 +98,7 @@ public SearchResponse find(IndividualSearch searchObject, Integer li return findByRadius(query, searchObject, includeDeleted, paramsMap); } if (searchObject.getIdentifier() == null) { - String queryWithoutLimit = query.replace("ORDER BY id ASC LIMIT :limit OFFSET :offset", ""); + String queryWithoutLimit = query.replace("ORDER BY createdtime DESC LIMIT :limit OFFSET :offset", ""); Long totalCount = constructTotalCountCTEAndReturnResult(queryWithoutLimit, paramsMap, this.namedParameterJdbcTemplate); List individuals = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); if (!individuals.isEmpty()) { @@ -226,7 +226,7 @@ private String getQueryForIndividual(IndividualSearch searchObject, Integer limi query = query.replace(tableName + " AND", tableName + " WHERE "); } if (searchObject.getIndividualName() != null) { - query = query + "AND givenname LIKE :individualName "; + query = query + "AND givenname ILIKE :individualName "; paramsMap.put("individualName", "%"+searchObject.getIndividualName()+"%"); } if (searchObject.getGender() != null) { diff --git a/health-services/libraries/health-services-common/pom.xml b/health-services/libraries/health-services-common/pom.xml index 17c27125802..5bdd15176c3 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.19-SNAPSHOT + 1.0.20-SNAPSHOT Shared classes among services @@ -115,7 +115,13 @@ org.egov.common health-services-models - 1.0.22-SNAPSHOT + 1.0.23-dev-SNAPSHOT + compile + + + org.egov + mdms-client + 2.9.0-SNAPSHOT compile 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 537a82400cc..269a15e449d 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 @@ -4,6 +4,7 @@ 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.models.core.SearchResponse; import org.egov.common.producer.Producer; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; @@ -23,6 +24,7 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; import static org.egov.common.utils.CommonUtils.getIdMethod; import static org.egov.common.utils.CommonUtils.getMethod; import static org.egov.common.utils.CommonUtils.getObjClass; @@ -236,6 +238,52 @@ public void putInCache(List objects, String key) { cacheByKey(objects, key); } + /** + * Finds entities based on search criteria, also returns the count of entities found. + * + * @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 with total count. + * @throws QueryBuilderException If an error occurs while building the query. + */ + public SearchResponse findWithCount(Object 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")) { + query = query.replace(tableName + " AND", tableName + " WHERE"); + } + if (Boolean.FALSE.equals(includeDeleted)) { + query += "AND isDeleted=:isDeleted "; + } + if (lastChangedSince != null) { + query += "AND lastModifiedTime>=:lastModifiedTime "; + } + query += "ORDER BY id ASC"; + Map paramsMap = selectQueryBuilder.getParamsMap(); + paramsMap.put("tenantId", tenantId); + paramsMap.put("isDeleted", includeDeleted); + paramsMap.put("lastModifiedTime", lastChangedSince); + + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, namedParameterJdbcTemplate); + + query += " LIMIT :limit OFFSET :offset"; + paramsMap.put("limit", limit); + paramsMap.put("offset", offset); + + List resultantList = namedParameterJdbcTemplate.query(query, paramsMap, rowMapper); + + return SearchResponse.builder().response(resultantList).totalCount(totalCount).build(); + } + /** * Finds entities based on search criteria. * diff --git a/health-services/libraries/health-services-models/CHANGELOG.md b/health-services/libraries/health-services-models/CHANGELOG.md index c7476cbe79b..e08569ca889 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.25 - 2025-01-03 +- Added BeneficiaryType Enum and update in ProjectType, Target models +- Added HouseHoldType Enum and added in Household, HouseholdSearch models +- Added DownsyncCLFHousehold, DownsyncCLFHouseholdResponse, HouseholdMemberMap +- Updated DownsyncCriteria to include householdId + ## 1.0.21 - 2024-08-07 - Added UserActionEnum, UserAction Entities, TaskStatus enum - Added isCascadingProjectDateUpdate in ProjectRequest model diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index cae31ed2480..0e75c7fbe97 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.22-SNAPSHOT + 1.0.25-dev-SNAPSHOT 17 ${java.version} @@ -84,4 +84,4 @@ https://nexus-repo.digit.org/nexus/content/repositories/snapshots/ - \ No newline at end of file + 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 4209e6e2311..e1550174657 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 @@ -14,27 +14,42 @@ import org.springframework.validation.annotation.Validated; /** - * FacilityResponse + * Represents a bulk response for facilities, including response metadata and a list of facilities. */ @Validated - - @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) public class FacilityBulkResponse { + + /** + * Metadata about the API response, including request details and status. + */ @JsonProperty("ResponseInfo") @NotNull @Valid private org.egov.common.contract.response.ResponseInfo responseInfo = null; + /** + * List of facilities returned in the response. + */ @JsonProperty("Facilities") @Valid private List facilities = null; + /** + * Total number of facilities in the response, defaults to 0. + */ + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + /** + * Adds a single facility to the list and returns the updated response. + */ public FacilityBulkResponse addFacilityItem(Facility facilityItem) { if (this.facilities == null) { this.facilities = new ArrayList<>(); @@ -42,6 +57,4 @@ public FacilityBulkResponse addFacilityItem(Facility facilityItem) { this.facilities.add(facilityItem); return this; } - } - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseHoldType.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseHoldType.java new file mode 100644 index 00000000000..77948226c61 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseHoldType.java @@ -0,0 +1,31 @@ +package org.egov.common.models.household; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public enum HouseHoldType { + + FAMILY("FAMILY"), + + COMMUNITY("COMMUNITY"), + + OTHER("OTHER"); + + private String value; + + HouseHoldType(String value) { + this.value = value; + } + + @JsonCreator + public static HouseHoldType fromValue(String text) { + for (HouseHoldType b : HouseHoldType.values()) { + if (String.valueOf(b.value).equalsIgnoreCase(text)) { + return b; + } + } + return null; + } + +} \ No newline at end of file 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 63c982ff07f..f43bc53e2f2 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 @@ -27,13 +27,16 @@ public class Household extends EgovOfflineModel { @JsonProperty("memberCount") @NotNull - @Range(min = 0, max = 1000) +// @Range(min = 0, max = 1000) private Integer memberCount = null; @JsonProperty("address") @Valid private Address address = null; + @JsonProperty("householdType") + private HouseHoldType householdType = null; + //TODO remove @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; 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 4ff5ccec51e..a6d754e3b99 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 @@ -37,6 +37,9 @@ public class HouseholdSearch extends EgovOfflineSearchModel { @DecimalMax("180") private Double longitude = null; + @JsonProperty("householdType") + private String householdType = null; + /* * @value unit of measurement in Kilometer * */ 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 6ed081c182e..60647504677 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 @@ -15,11 +15,10 @@ import org.springframework.validation.annotation.Validated; /** - * IndividualResponse + * IndividualBulkResponse represents the response structure for bulk operations related to individuals. + * It encapsulates the response information, total count of individuals, and a list of individual objects. */ @Validated - - @Data @NoArgsConstructor @AllArgsConstructor @@ -27,20 +26,35 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class IndividualBulkResponse { + /** + * Metadata about the API response, including details like request status and other information. + */ @JsonProperty("ResponseInfo") @NotNull @Valid private ResponseInfo responseInfo = null; + /** + * Total count of individual records in the response, defaults to 0 if not specified. + */ @JsonProperty("TotalCount") @Valid @Builder.Default private Long totalCount = 0L; - + + /** + * List of individual records returned in the response. + */ @JsonProperty("Individual") @Valid private List individual = null; + /** + * Adds a single individual record to the list and returns the updated response. + * + * @param individualItem The individual record to add to the list. + * @return The updated IndividualBulkResponse instance. + */ public IndividualBulkResponse addIndividualItem(Individual individualItem) { if (this.individual == null) { this.individual = new ArrayList<>(); @@ -48,6 +62,4 @@ public IndividualBulkResponse addIndividualItem(Individual individualItem) { this.individual.add(individualItem); return this; } - } - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryType.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryType.java new file mode 100644 index 00000000000..3836a8c5168 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryType.java @@ -0,0 +1,35 @@ +package org.egov.common.models.project; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + + +public enum BeneficiaryType { + + HOUSEHOLD("HOUSEHOLD"), + + INDIVIDUAL("INDIVIDUAL"); + + private String value; + + BeneficiaryType(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static BeneficiaryType fromValue(String text) { + for(BeneficiaryType a:BeneficiaryType.values()){ + if(String.valueOf(a.value).equalsIgnoreCase(text)){ + return a; + } + } + + return null; + } +} \ No newline at end of file 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 3b7c899ebfe..38d1df9eafa 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 @@ -15,29 +15,46 @@ import org.springframework.validation.annotation.Validated; /** - * ProjectFacilityResponse + * Represents a bulk response for project facilities, including response metadata and a list of facilities. */ @Validated - - @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) public class ProjectFacilityBulkResponse { + + /** + * Metadata about the API response, including request details and status. + */ @JsonProperty("ResponseInfo") @NotNull @Valid private ResponseInfo responseInfo = null; + /** + * Total number of project facilities in the response, defaults to 0. + */ + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + + /** + * List of project facilities returned in the response. + */ @JsonProperty("ProjectFacilities") @NotNull @Valid private List projectFacilities = new ArrayList<>(); + /** + * Adds a single project facility to the list and returns the updated response. + */ public ProjectFacilityBulkResponse addProjectFacilityItem(ProjectFacility projectFacilityItem) { this.projectFacilities.add(projectFacilityItem); return this; } } + 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 2fdba28281a..7aef41e322b 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 @@ -37,6 +37,11 @@ public class ProjectResourceBulkResponse { @Valid private List projectResource = new ArrayList<>(); + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + public ProjectResourceBulkResponse addProjectResourceItem(ProjectResource projectResourceItem) { this.projectResource.add(projectResourceItem); return this; 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 73d80462fb0..49070e25a94 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 @@ -15,11 +15,9 @@ import org.springframework.validation.annotation.Validated; /** -* ProjectStaffResponse -*/ + * Represents a bulk response for project staff, containing response metadata and a list of staff members. + */ @Validated - - @Data @NoArgsConstructor @AllArgsConstructor @@ -27,19 +25,38 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class ProjectStaffBulkResponse { + /** + * Metadata about the API response, including request status and other information. + */ @JsonProperty("ResponseInfo") @NotNull @Valid private ResponseInfo responseInfo = null; + /** + * List of project staff members returned in the response. + */ @JsonProperty("ProjectStaff") @NotNull @Valid private List projectStaff = new ArrayList<>(); + /** + * Total number of project staff members in the response, defaults to 0 if not specified. + */ + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + + /** + * Adds a single project staff member to the list and returns the updated response. + * + * @param projectStaffItem The project staff member to add to the list. + * @return The updated ProjectStaffBulkResponse instance. + */ public ProjectStaffBulkResponse addProjectStaffItem(ProjectStaff projectStaffItem) { this.projectStaff.add(projectStaffItem); return this; } } - 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 78445bed4a9..6f781df0f5a 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 @@ -48,7 +48,7 @@ public class ProjectType { private String group = null; @JsonProperty("beneficiaryType") - private String beneficiaryType = null; + private BeneficiaryType beneficiaryType = null; @JsonProperty("eligibilityCriteria") @Size(max=10) 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 e7152211048..187648724a6 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 @@ -31,7 +31,7 @@ public class Target { private String projectid = null; @JsonProperty("beneficiaryType") - private String beneficiaryType = null; + private BeneficiaryType beneficiaryType = null; @JsonProperty("totalNo") private Integer totalNo = null; 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 index 4c6ad63a53f..0e2051b6be6 100644 --- 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 @@ -1,5 +1,7 @@ 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; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncCLFHousehold.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncCLFHousehold.java new file mode 100644 index 00000000000..c0ccef312fe --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncCLFHousehold.java @@ -0,0 +1,24 @@ +package org.egov.common.models.referralmanagement.beneficiarydownsync; + +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; +import java.util.Map; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder + +public class DownsyncCLFHousehold { + @JsonProperty("HouseholdCountMap") + List householdMemberCountMap; + + @JsonProperty("DownsyncCriteria") + DownsyncCriteria downsyncCriteria; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncCLFHouseholdResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncCLFHouseholdResponse.java new file mode 100644 index 00000000000..97a3023163e --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncCLFHouseholdResponse.java @@ -0,0 +1,24 @@ +package org.egov.common.models.referralmanagement.beneficiarydownsync; + +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 java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder + +public class DownsyncCLFHouseholdResponse { + + @JsonProperty("ResponseInfo") + private ResponseInfo responseInfo; + + @JsonProperty("Households") + private DownsyncCLFHousehold Households; +} 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 71816f7849f..400de52948b 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 @@ -35,5 +35,7 @@ public class DownsyncCriteria { private Integer limit = 50; private Long totalCount; + + private String householdId; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/HouseholdMemberMap.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/HouseholdMemberMap.java new file mode 100644 index 00000000000..ee6819f59ec --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/HouseholdMemberMap.java @@ -0,0 +1,20 @@ +package org.egov.common.models.referralmanagement.beneficiarydownsync; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.models.household.Household; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class HouseholdMemberMap { + + private Household household; + + private Integer numberOfMembers; + + +} \ No newline at end of file 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 a561ef4f8a4..d8791d66979 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 @@ -13,21 +13,39 @@ import lombok.NoArgsConstructor; import org.egov.common.contract.response.ResponseInfo; +/** + * Represents a bulk response for HF (Health Facility) referrals, containing response metadata and a list of referrals. + */ @Data @NoArgsConstructor @AllArgsConstructor @Builder public class HFReferralBulkResponse { + + /** + * Metadata about the API response, including details such as request status and information. + */ @JsonProperty("ResponseInfo") @NotNull @Valid private ResponseInfo responseInfo; + /** + * List of health facility referrals returned in the response. + */ @JsonProperty("HFReferrals") @NotNull @Valid private List hfReferrals; + /** + * Total number of HF referrals in the response, defaults to 0 if not specified. + */ + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + /** * Add a HfReferral item to the list of HfReferrals in the bulk response. * 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 3f52835a270..3ad45bc8ed7 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 @@ -14,11 +14,9 @@ import org.springframework.validation.annotation.Validated; /** - * StockResponse + * Represents a bulk response for stock items, containing response metadata and a list of stock entries. */ @Validated - - @Data @NoArgsConstructor @AllArgsConstructor @@ -26,20 +24,40 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class StockBulkResponse { + /** + * Metadata about the API response, including details such as request status and information. + */ @JsonProperty("ResponseInfo") @NotNull @Valid private org.egov.common.contract.response.ResponseInfo responseInfo = null; + /** + * List of stock items returned in the response. + */ @JsonProperty("Stock") @NotNull @Valid private List stock = new ArrayList<>(); - + /** + * Total number of stock items in the response, defaults to 0 if not specified. + */ + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + + /** + * Adds a single stock item to the list of stock and returns the updated response. + * + * @param stockItem The stock item to add to the list. + * @return The updated StockBulkResponse instance. + */ public StockBulkResponse addStockItem(Stock stockItem) { this.stock.add(stockItem); return this; } } + 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 17ea81e8ed7..bae326d2dd8 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 @@ -14,11 +14,9 @@ import org.springframework.validation.annotation.Validated; /** - * StockReconciliationResponse + * Represents a bulk response for stock reconciliation, containing response metadata and a list of stock reconciliation entries. */ @Validated - - @Data @NoArgsConstructor @AllArgsConstructor @@ -26,19 +24,38 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class StockReconciliationBulkResponse { + /** + * Metadata about the API response, including details such as request status and information. + */ @JsonProperty("ResponseInfo") @NotNull @Valid private org.egov.common.contract.response.ResponseInfo responseInfo = null; + /** + * List of stock reconciliation items returned in the response. + */ @JsonProperty("StockReconciliation") @NotNull @Valid private List stockReconciliation = new ArrayList<>(); + /** + * Total number of stock reconciliation items in the response, defaults to 0 if not specified. + */ + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + + /** + * Adds a single stock reconciliation item to the list and returns the updated response. + * + * @param stockReconciliationItem The stock reconciliation item to add to the list. + * @return The updated StockReconciliationBulkResponse instance. + */ public StockReconciliationBulkResponse addStockReconciliationItem(StockReconciliation stockReconciliationItem) { this.stockReconciliation.add(stockReconciliationItem); return this; } } - diff --git a/health-services/plan-service/CHANGELOG.md b/health-services/plan-service/CHANGELOG.md index 650d79eae57..a73439d7658 100644 --- a/health-services/plan-service/CHANGELOG.md +++ b/health-services/plan-service/CHANGELOG.md @@ -1,10 +1,38 @@ # 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 +## 1.0.0 - 2024-12-03 +### Plan Service + +##### Plan Configuration + +1. Validation of Plan Configuration: Validates all plan configuration requests against MDMS and Project Factory before processing the requests. +2. Plan Configuration Create: Validates and enriches new plan configurations before publishing them to the Kafka topic for asynchronous processing. +3. Plan Configuration Update: Updates existing plan configurations post-validation and enrichment by pushing requests to the Kafka update topic. +4. Plan Configuration Search: Facilitates searching for plan configurations using the provided search criteria. +5. Resource Generator Consumer: Listens to resource generator plan configuration update topic to update plan configuration. + +#### Plan + +1. Plan 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. +6. Plan Bulk Update: Allows updating multiple plans in a single operation after validation. +7. Resource Generator Consumer: Listens to resource plan create topic to trigger the creation of new plans. + +#### Plan Facility + +1. Validation: Validates plan facility requests against MDMS, Facility Service and Project Factory before processing the requests. +2. Plan Facility Create: Creates a plan facility after validation and enrichment, pushing the create request to the designated kafka topic. +3. Plan Facility Update: Updates existing facilities post-validation by pushing update requests to the Kafka topic. Also sends the update request to Census service for facility mapping. +4. Plan Facility Search: Searches Plan Facility for the provided search criteria. +5. Project Factory Consumer: Listens to project factory consumer to enrich and create new plan facility. + +#### Plan Employee Assignment + +1. Validation: Validates plan employee assignment requests against MDMS, User service and Project Factory before processing the requests. +2. Plan Employee Assignment Create: Assigns employees to plans post-validation and enrichment, considering roles and jurisdictions by pushing request to create kafka topic. +3. Plan Employee Assignment Update: Updates existing assignments after validation, publishing the changes to the designated Kafka update topic. +4. Plan Employee Assignment Search: Enables searching for employee assignments using provided search criteria. \ No newline at end of file diff --git a/health-services/plan-service/pom.xml b/health-services/plan-service/pom.xml index 148766ff97d..c41f44a9f05 100644 --- a/health-services/plan-service/pom.xml +++ b/health-services/plan-service/pom.xml @@ -95,6 +95,11 @@ 2.9.0-SNAPSHOT compile + + org.apache.commons + commons-text + 1.10.0 + diff --git a/health-services/plan-service/src/main/java/digit/config/Configuration.java b/health-services/plan-service/src/main/java/digit/config/Configuration.java index 7cf4b3549f7..110be35646a 100644 --- a/health-services/plan-service/src/main/java/digit/config/Configuration.java +++ b/health-services/plan-service/src/main/java/digit/config/Configuration.java @@ -1,16 +1,13 @@ package digit.config; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.*; import org.egov.tracer.config.TracerConfiguration; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.stereotype.Component; -import java.util.TimeZone; +import java.util.List; +import java.util.Map; @Component @Data @@ -21,6 +18,13 @@ @Getter public class Configuration { + //Role Map + @Value("#{${role.map}}") + public Map roleMap; + + @Value("${plan.estimation.approver.roles}") + public List planEstimationApproverRoles; + //MDMS @Value("${egov.mdms.host}") private String mdmsHost; @@ -28,6 +32,32 @@ public class Configuration { @Value("${egov.mdms.search.endpoint}") private String mdmsEndPoint; + @Value("${egov.mdms.search.v2.endpoint}") + private String mdmsV2EndPoint; + + //Project Factory + @Value("${egov.project.factory.host}") + private String projectFactoryHost; + + @Value("${egov.project.factory.search.endpoint}") + private String projectFactorySearchEndPoint; + + //User Service + @Value("${egov.user.service.host}") + private String userServiceHost; + + @Value("${egov.user.search.endpoint}") + private String userSearchEndPoint; + + // Boundary Service + @Value("${egov.boundary.service.host}") + private String boundaryServiceHost; + + @Value("${egov.boundary.relationship.search.endpoint}") + private String boundaryRelationshipSearchEndpoint; + + @Value("${egov.boundary.hierarchy.search.endpoint}") + private String boundaryHierarchySearchEndpoint; //Persister Topic @Value("${plan.configuration.create.topic}") @@ -36,16 +66,64 @@ public class Configuration { @Value("${plan.configuration.update.topic}") private String planConfigUpdateTopic; + @Value("${plan.employee.assignment.create.topic}") + private String planEmployeeAssignmentCreateTopic; + + @Value("${plan.employee.assignment.update.topic}") + private String planEmployeeAssignmentUpdateTopic; + @Value("${plan.create.topic}") private String planCreateTopic; @Value("${plan.update.topic}") private String planUpdateTopic; + @Value("${plan.bulk.update.topic}") + private String planBulkUpdateTopic; + + @Value("${plan.facility.create.topic}") + private String planFacilityCreateTopic; + + @Value("${plan.facility.update.topic}") + private String planFacilityUpdateTopic; + @Value("${plan.default.offset}") private Integer defaultOffset; @Value("${plan.default.limit}") private Integer defaultLimit; + //Census + @Value("${egov.census.host}") + private String censusHost; + + @Value("${egov.census.search.endpoint}") + private String censusSearchEndPoint; + + //Facility + @Value("${egov.facility.host}") + private String facilityHost; + + @Value("${egov.facility.search.endpoint}") + private String facilitySearchEndPoint; + + //Workflow + @Value("${egov.workflow.host}") + private String wfHost; + + @Value("${egov.workflow.transition.path}") + private String wfTransitionPath; + + @Value("${egov.business.service.search.endpoint}") + private String businessServiceSearchEndpoint; + + @Value("${workflow.initiate.action}") + private List wfInitiateActions; + + @Value("${workflow.intermediate.action}") + private List wfIntermediateActions; + + @Value("${workflow.send.back.actions}") + private List wfSendBackActions; + } diff --git a/health-services/plan-service/src/main/java/digit/config/ServiceConstants.java b/health-services/plan-service/src/main/java/digit/config/ServiceConstants.java index ab694a05961..a2b9696b482 100644 --- a/health-services/plan-service/src/main/java/digit/config/ServiceConstants.java +++ b/health-services/plan-service/src/main/java/digit/config/ServiceConstants.java @@ -12,21 +12,41 @@ public class ServiceConstants { public static final String ERROR_WHILE_FETCHING_FROM_MDMS = "Exception occurred while fetching category lists from mdms: "; + public static final String ERROR_WHILE_FETCHING_FROM_USER_SERVICE = "Exception occurred while fetching user details from user service: "; + + public static final String ERROR_WHILE_FETCHING_FROM_PROJECT_FACTORY = "Exception occurred while fetching campaign details from project factory: "; + + public static final String ERROR_WHILE_FETCHING_FROM_CENSUS = "Exception occurred while fetching records from census: "; + + public static final String ERROR_WHILE_FETCHING_BOUNDARY_DETAILS = "Exception occurred while fetching boundary relationship from boundary service: "; + + public static final String ERROR_WHILE_FETCHING_BOUNDARY_HIERARCHY_DETAILS = "Exception occurred while fetching boundary hierarchy details from boundary service: "; + + public static final String ERROR_WHILE_FETCHING_DATA_FROM_HRMS = "Exception occurred while fetching employee from hrms: "; + public static final String RES_MSG_ID = "uief87324"; public static final String SUCCESSFUL = "successful"; public static final String FAILED = "failed"; + public static final String ROOT_PREFIX = "ROOT"; + public static final String USERINFO_MISSING_CODE = "USERINFO_MISSING"; public static final String USERINFO_MISSING_MESSAGE = "UserInfo is missing in Request Info "; public static final String ASSUMPTION_VALUE_NOT_FOUND_CODE = "ASSUMPTION_VALUE_NOT_FOUND"; - public static final String ASSUMPTION_VALUE_NOT_FOUND_MESSAGE = "Operation's Assumption value not found in active assumptions list "; - - public static final String FILESTORE_ID_INVALID_CODE = "FILESTORE_ID_INVALID"; - public static final String FILESTORE_ID_INVALID_MESSAGE = " Resource mapping does not have a Valid File Store Id "; + public static final String ASSUMPTION_VALUE_NOT_FOUND_MESSAGE = "Operation's Assumption value is not present in allowed columns, previous outputs, or active Assumption Keys "; public static final String ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_CODE = "ASSUMPTION_KEY_NOT_FOUND_IN_MDMS"; - public static final String ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_MESSAGE = "Assumption Key is not present in MDMS "; + public static final String ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_MESSAGE = "Assumption Key is not present in MDMS - "; + + public static final String DUPLICATE_ASSUMPTION_KEY_CODE = "DUPLICATE_ASSUMPTION_KEY"; + public static final String DUPLICATE_ASSUMPTION_KEY_MESSAGE = "Duplicate Assumption key found : "; + + public static final String VEHICLE_ID_NOT_FOUND_IN_MDMS_CODE = "VEHICLE_ID_NOT_FOUND_IN_MDMS"; + public static final String VEHICLE_ID_NOT_FOUND_IN_MDMS_MESSAGE = "Vehicle Id is not present in MDMS"; + + public static final String VEHICLE_IDS_INVALID_DATA_TYPE_CODE = "VEHICLE_IDS_INVALID_DATA_TYPE"; + public static final String VEHICLE_IDS_INVALID_DATA_TYPE_MESSAGE = "Vehicle IDs should be a list of strings."; public static final String TEMPLATE_IDENTIFIER_NOT_FOUND_IN_MDMS_CODE = "TEMPLATE_IDENTIFIER_NOT_FOUND_IN_MDMS"; public static final String TEMPLATE_IDENTIFIER_NOT_FOUND_IN_MDMS_MESSAGE = "Template Identifier is not present in MDMS "; @@ -38,29 +58,72 @@ public class ServiceConstants { public static final String ONLY_ONE_FILE_OF_REQUIRED_TEMPLATE_IDENTIFIER_MESSAGE = "Only one file of the required template identifier should be present "; public static final String INPUT_KEY_NOT_FOUND_CODE = "INPUT_KEY_NOT_FOUND"; - public static final String INPUT_KEY_NOT_FOUND_MESSAGE = "Operation's Input key not present in MDMS "; - - public static final String LOCALITY_NOT_PRESENT_IN_MAPPED_TO_CODE = "LOCALITY_NOT_PRESENT_IN_MAPPED_TO"; - public static final String LOCALITY_NOT_PRESENT_IN_MAPPED_TO_MESSAGE = "Resource Mapping's MappedTo must contain 'Locality' "; - - public static final String DUPLICATE_MAPPED_TO_VALIDATION_ERROR_CODE = "DUPLICATE_MAPPED_TO_VALIDATION_ERROR"; - public static final String DUPLICATE_MAPPED_TO_VALIDATION_ERROR_MESSAGE = "Duplicate MappedTo found in Resource Mapping"; - - public static final String TENANT_NOT_FOUND_IN_MDMS_CODE = "TENANT_ID_NOT_FOUND_IN_MDMS"; - public static final String TENANT_NOT_FOUND_IN_MDMS_MESSAGE = "Tenant Id is not present in MDMS"; + public static final String INPUT_KEY_NOT_FOUND_MESSAGE = "Operation's Input key is not present in allowed columns or previous outputs - "; public static final String TENANT_ID_EMPTY_CODE = "TENANT_ID_EMPTY"; public static final String TENANT_ID_EMPTY_MESSAGE = "Tenant Id cannot be empty, TenantId should be present"; + public static final String PLAN_CONFIG_ID_EMPTY_CODE = "PLAN_CONFIG_ID_EMPTY"; + public static final String PLAN_CONFIG_ID_EMPTY_MESSAGE = "Plan config Id cannot be empty."; + 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 INVALID_EMPLOYEE_ID_CODE = "INVALID_EMPLOYEE_ID"; + public static final String INVALID_EMPLOYEE_ID_MESSAGE = "Invalid or incorrect employee id."; + + public static final String NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_CODE = "NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID"; + public static final String NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_MESSAGE = "Invalid or incorrect campaign id. No campaign details found for provided campaign id."; + + public static final String NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_CODE = "NO_CENSUS_FOUND_FOR_GIVEN_DETAILS"; + public static final String NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_MESSAGE = "Census records does not exists for the given details: "; + + + public static final String INVALID_ROOT_EMPLOYEE_JURISDICTION_CODE = "INVALID_ROOT_EMPLOYEE_JURISDICTION"; + public static final String INVALID_ROOT_EMPLOYEE_JURISDICTION_MESSAGE = "The root employee's jurisdiction should be at highest hierarchy"; + + public static final String INVALID_EMPLOYEE_JURISDICTION_CODE = "INVALID_EMPLOYEE_JURISDICTION"; + public static final String INVALID_EMPLOYEE_JURISDICTION_MESSAGE = "The employee's jurisdiction can't be at highest or lowest hierarchy"; + + public static final String INVALID_JURISDICTION_CODE = "INVALID_JURISDICTION"; + public static final String INVALID_JURISDICTION_MESSAGE = "The employee's jurisdiction provided is invalid"; + + public static final String INVALID_HIERARCHY_LEVEL_CODE = "INVALID_HIERARCHY_LEVEL"; + public static final String INVALID_HIERARCHY_LEVEL_MESSAGE = "The hierarchy level provided is invalid"; + + public static final String INVALID_EMPLOYEE_ROLE_CODE = "INVALID_EMPLOYEE_ROLE"; + public static final String INVALID_EMPLOYEE_ROLE_MESSAGE = "The employee's role provided is invalid"; + public static final String SEARCH_CRITERIA_EMPTY_CODE = "SEARCH_CRITERIA_EMPTY"; public static final String SEARCH_CRITERIA_EMPTY_MESSAGE = "Search criteria cannot be empty"; public static final String INVALID_PLAN_CONFIG_ID_CODE = "INVALID_PLAN_CONFIG_ID"; public static final String INVALID_PLAN_CONFIG_ID_MESSAGE = "Plan config id provided is invalid"; + public static final String INVALID_PLAN_EMPLOYEE_ASSIGNMENT_CODE = "INVALID_PLAN_EMPLOYEE_ASSIGNMENT"; + public static final String INVALID_PLAN_EMPLOYEE_ASSIGNMENT_MESSAGE = "Plan employee assignment to be updated doesn't exists"; + + public static final String PLAN_CONFIGURATION_ALREADY_EXISTS_CODE = "PLAN_CONFIGURATION_ALREADY_EXISTS"; + public static final String PLAN_CONFIGURATION_ALREADY_EXISTS_MESSAGE = "Plan Configuration for the provided name and campaign id already exists"; + + public static final String PLAN_EMPLOYEE_ASSIGNMENT_ALREADY_EXISTS_CODE = "PLAN_EMPLOYEE_ASSIGNMENT_ALREADY_EXISTS"; + public static final String PLAN_EMPLOYEE_ASSIGNMENT_ALREADY_EXISTS_MESSAGE = "Plan employee assignment for the provided details already exists"; + + public static final String PLAN_FACILITY_LINKAGE_ALREADY_EXISTS_CODE = "PLAN_FACILITY_LINKAGE_ALREADY_EXISTS"; + public static final String PLAN_FACILITY_LINKAGE_ALREADY_EXISTS_MESSAGE = "Plan facility linkage for the provided facilityId and planConfigId already exists"; + + public static final String PLAN_EMPLOYEE_ASSIGNMENT_ID_EMPTY_CODE = "PLAN_EMPLOYEE_ASSIGNMENT_ID_EMPTY"; + public static final String PLAN_EMPLOYEE_ASSIGNMENT_ID_EMPTY_MESSAGE = "Plan employee assignment id cannot be empty"; + + public static final String PLAN_EMPLOYEE_ASSIGNMENT_NOT_FOUND_CODE = "PLAN_EMPLOYEE_ASSIGNMENT_FOR_BOUNDARY_NOT_FOUND"; + public static final String PLAN_EMPLOYEE_ASSIGNMENT_NOT_FOUND_MESSAGE = "No plan-employee assignment found for the provided boundary - "; + + public static final String JURISDICTION_NOT_FOUND_CODE = "JURISDICTION_NOT_FOUND"; + public static final String JURISDICTION_NOT_FOUND_MESSAGE = "Employee doesn't have the jurisdiction to take action for the provided locality."; + + public static final String NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_CODE = "NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE"; + public static final String NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_MESSAGE = "Invalid or incorrect boundaryCode. No boundary data found."; + public static final String METRIC_NOT_FOUND_IN_MDMS_CODE = "METRIC_NOT_FOUND_IN_MDMS"; public static final String METRIC_NOT_FOUND_IN_MDMS_MESSAGE = "Metric key not found in MDMS"; @@ -73,9 +136,6 @@ public class ServiceConstants { public static final String JSONPATH_ERROR_CODE = "JSONPATH_ERROR"; public static final String JSONPATH_ERROR_MESSAGE = "Failed to parse mdms response with given Jsonpath" ; - public static final String BOUNDARY_CODE_MAPPING_NOT_FOUND_CODE = "BOUNDARY_CODE_MAPPING_NOT_FOUND"; - public static final String BOUNDARY_CODE_MAPPING_NOT_FOUND_MESSAGE = "Boundary Code Mapping is required column is not found."; - public static final String NAME_VALIDATION_LIST_EMPTY_CODE = "NAME_VALIDATION_LIST_EMPTY"; public static final String NAME_VALIDATION_LIST_EMPTY_MESSAGE = "Name Validation list from MDMS is empty"; @@ -109,9 +169,6 @@ public class ServiceConstants { public static final String PLAN_RESOURCES_MANDATORY_CODE = "PLAN_RESOURCES_MANDATORY"; public static final String PLAN_RESOURCES_MANDATORY_MESSAGE = "Resources are mandatory if plan configuration id is not provided"; - public static final String PLAN_RESOURCES_NOT_ALLOWED_CODE = "PLAN_RESOURCES_NOT_ALLOWED"; - public static final String PLAN_RESOURCES_NOT_ALLOWED_MESSAGE = "Resources are not allowed if plan configuration id is provided"; - public static final String INVALID_RESOURCE_ACTIVITY_LINKAGE_CODE = "INVALID_RESOURCE_ACTIVITY_LINKAGE"; public static final String INVALID_RESOURCE_ACTIVITY_LINKAGE_MESSAGE = "Resource-Activity linkage is invalid"; @@ -127,9 +184,38 @@ public class ServiceConstants { public static final String DUPLICATE_ACTIVITY_UUIDS_CODE = "DUPLICATE_ACTIVITY_UUIDS"; public static final String DUPLICATE_ACTIVITY_UUIDS_MESSAGE = "Activity UUIDs should be unique"; + public static final String ADDITIONAL_DETAILS_MISSING_CODE = "ADDITIONAL_DETAILS_MISSING"; + public static final String ADDITIONAL_DETAILS_MISSING_MESSAGE = "Additional details are missing in the plan configuration request."; + + public static final String PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_CODE = "PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT"; + public static final String PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_MESSAGE = "Key is not present in json object - "; + + public static final String ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_CODE = "ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS"; + public static final String ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_MESSAGE = "Exception occurred while updating additional details : "; + + public static final String WORKFLOW_INTEGRATION_ERROR_CODE = "WORKFLOW_INTEGRATION_ERROR"; + public static final String WORKFLOW_INTEGRATION_ERROR_MESSAGE = "Exception occured while integrating with workflow : "; + + public static final String PROCESS_INSTANCE_NOT_FOUND_CODE = "PROCESS_INSTANCE_NOT_FOUND"; + public static final String PROCESS_INSTANCE_NOT_FOUND_MESSAGE = "No process instance found with businessId: "; + + public static final String FILES_NOT_FOUND_CODE = "FILES_NOT_FOUND"; + public static final String FILES_NOT_FOUND_MESSAGE = "Files are not present in Plan Configuration."; + + public static final String ASSUMPTIONS_NOT_FOUND_CODE = "ASSUMPTIONS_NOT_FOUND"; + public static final String ASSUMPTIONS_NOT_FOUND_MESSAGE = "Assumptions are not present in Plan Configuration."; + + public static final String OPERATIONS_NOT_FOUND_CODE = "OPERATIONS_NOT_FOUND"; + public static final String OPERATIONS_NOT_FOUND_MESSAGE = "Operations are not present in Plan Configuration."; + + public static final String NO_BUSINESS_SERVICE_DATA_FOUND_CODE = "NO_BUSINESS_SERVICE_DATA_FOUND"; + public static final String NO_BUSINESS_SERVICE_DATA_FOUND_MESSAGE = "Invalid or incorrect businessService. No business service data found."; //mdms constants public static final String MDMS_PLAN_MODULE_NAME = "hcm-microplanning"; + public static final String MDMS_ADMIN_CONSOLE_MODULE_NAME = "HCM-ADMIN-CONSOLE"; + public static final String MDMS_MASTER_HIERARCHY_CONFIG = "hierarchyConfig"; + public static final String MDMS_MASTER_HIERARCHY_SCHEMA = "HierarchySchema"; public static final String MDMS_MASTER_ASSUMPTION = "HypothesisAssumptions"; public static final String MDMS_MASTER_UPLOAD_CONFIGURATION = "UploadConfiguration"; public static final String MDMS_MASTER_RULE_CONFIGURE_INPUTS = "RuleConfigureInputs"; @@ -137,6 +223,17 @@ public class ServiceConstants { public static final String MDMS_MASTER_METRIC = "Metric"; public static final String MDMS_MASTER_UOM = "Uom"; public static final String MDMS_MASTER_NAME_VALIDATION= "MicroplanNamingRegex"; + public static final String MDMS_SCHEMA_ADMIN_SCHEMA = "adminSchema"; + public static final String BOUNDARY = "boundary"; + public static final String HIERARCHY_TYPE = "hierarchyType"; + + //MDMS field Constants + public static final String PROPERTIES = "properties"; + public static final String NUMBER_PROPERTIES = "numberProperties"; + public static final String STRING_PROPERTIES = "stringProperties"; + public static final String NAME = "name"; + + public static final String MICROPLAN_PREFIX = "MP-"; public static final String JSON_ROOT_PATH = "$."; @@ -144,10 +241,14 @@ public class ServiceConstants { public static final String DOT_REGEX = "\\."; + public static final String PIPE_REGEX = "\\|"; + public static final String FILTER_CODE = "$.*.code"; public static final String FILTER_ID = "$.*.id"; + public static final String FILTER_TO_GET_ALL_IDS = "*.id"; + public static final String FILTER_DATA = "$.*.data"; public static final String LOCALITY_CODE = "Locality"; @@ -163,8 +264,114 @@ public class ServiceConstants { public static final String MDMS_SCHEMA_PROPERTIES_IS_RULE_CONFIGURE_INPUT = "isRuleConfigureInputs"; public static final String MDMS_SCHEMA_PROPERTIES_IS_REQUIRED = "isRequired"; + + public static final String MDMS_SCHEMA_VEHICLE_DETAILS = "VehicleDetails"; + public static final String BOUNDARY_CODE = "boundaryCode"; + public static final String FILTER_ALL_ASSUMPTIONS = ".assumptionCategories[*].assumptions[*]"; + + public static final String HIERARCHY_CONFIG_FOR_MICROPLAN = "[?(@.type == 'microplan')]"; + + public static final String HIGHEST_HIERARCHY_FIELD_FOR_MICROPLAN = "highestHierarchy"; + + public static final String LOWEST_HIERARCHY_FIELD_FOR_MICROPLAN = "lowestHierarchy"; + public static final String NAME_VALIDATION_DATA = "Data"; + // Constants for constructing logical expressions or queries + public static final String AND = " && "; + public static final String EQUALS = " == "; + public static final String SINGLE_QUOTE = "'"; + + // JSON field constants for campaign details + public static final String JSON_FIELD_CAMPAIGN_TYPE = "campaignType"; + public static final String JSON_FIELD_DISTRIBUTION_PROCESS = "DistributionProcess"; + public static final String JSON_FIELD_REGISTRATION_PROCESS = "RegistrationProcess"; + public static final String JSON_FIELD_RESOURCE_DISTRIBUTION_STRATEGY_CODE = "resourceDistributionStrategyCode"; + public static final String JSON_FIELD_IS_REGISTRATION_AND_DISTRIBUTION_TOGETHER = "isRegistrationAndDistributionHappeningTogetherOrSeparately"; + public static final String JSON_FIELD_VEHICLE_ID = "vehicleIds"; + + // JSON path constants for campaign details + public static final String JSONPATH_FILTER_PREFIX = "[?("; + public static final String JSONPATH_FILTER_SUFFIX = ")]"; + public static final String JSON_PATH_FILTER_CAMPAIGN_TYPE = "@.campaignType"; + public static final String JSON_PATH_FILTER_DISTRIBUTION_PROCESS = "@.DistributionProcess"; + public static final String JSON_PATH_FILTER_REGISTRATION_PROCESS = "@.RegistrationProcess"; + public static final String JSON_PATH_FILTER_RESOURCE_DISTRIBUTION_STRATEGY_CODE = "@.resourceDistributionStrategyCode"; + public static final String JSON_PATH_FILTER_IS_REGISTRATION_AND_DISTRIBUTION_TOGETHER = "@.isRegistrationAndDistributionHappeningTogetherOrSeparately"; + + // Workflow Constants + public static final String PLAN_CONFIGURATION_BUSINESS_SERVICE = "PLAN_CONFIGURATION"; + + public static final String PLAN_ESTIMATION_BUSINESS_SERVICE = "PLAN_ESTIMATION"; + + public static final String MODULE_NAME_VALUE = "plan-service"; + + public static final String DRAFT_STATUS = "DRAFT"; + + public static final String SETUP_COMPLETED_ACTION = "INITIATE"; + + public static final String URI_TENANT_ID_PARAM = "tenantId"; + + public static final String URI_BUSINESS_SERVICE_PARAM = "businessService"; + + public static final String URI_BUSINESS_SERVICE_QUERY_TEMPLATE = "?tenantId={tenantId}&businessServices={businessService}"; + + public static final String APPROVE_CENSUS_DATA_ACTION = "APPROVE_CENSUS_DATA"; + + public static final String FINALIZE_CATCHMENT_MAPPING_ACTION = "FINALIZE_CATCHMENT_MAPPING"; + + public static final String APPROVE_ESTIMATIONS_ACTION = "APPROVE_ESTIMATIONS"; + + public static final String VALIDATED_STATUS = "VALIDATED"; + + //Query constants + public static final String PERCENTAGE_WILDCARD = "%"; + + public static final String MDMS_MASTER_HIERARCHY= "hierarchy"; + + public static final String ERROR_WHILE_FETCHING_FROM_FACILITY = "Exception occurred while fetching facility details from facility service "; + + public static final String ERROR_WHILE_FETCHING_BUSINESS_SERVICE_DETAILS = "Exception occurred while fetching business service details: "; + + public static final String INVALID_PLAN_FACILITY_ID_CODE = "INVALID_PLAN_FACILITY_ID"; + public static final String INVALID_PLAN_FACILITY_ID_MESSAGE = "Plan facility id provided is invalid"; + + public static final String INVALID_SERVICE_BOUNDARY_CODE = "INVALID_SERVICE_BOUNDARY"; + public static final String INVALID_SERVICE_BOUNDARY_MESSAGE = "The provided service boundary is invalid"; + + public static final String INVALID_RESIDING_BOUNDARY_CODE = "INVALID_RESIDING_BOUNDARY"; + public static final String INVALID_RESIDING_BOUNDARY_MESSAGE = "The provided residing boundary is invalid"; + + public static final String CANNOT_APPROVE_CENSUS_DATA_CODE = "CANNOT_APPROVE_CENSUS_DATA"; + public static final String CANNOT_APPROVE_CENSUS_DATA_MESSAGE = "Census data can't be approved until all the census records are validated"; + + public static final String CANNOT_APPROVE_ESTIMATIONS_CODE = "CANNOT_APPROVE_ESTIMATIONS"; + public static final String CANNOT_APPROVE_ESTIMATIONS_MESSAGE = "Estimations can't be approved until all the estimations are validated"; + + public static final String CANNOT_FINALIZE_CATCHMENT_MAPPING_CODE = "CANNOT_FINALIZE_CATCHMENT_MAPPING"; + public static final String CANNOT_FINALIZE_CATCHMENT_MAPPING_MESSAGE = "Catchment mapping can't be finalized until all boundaries have facility assigned"; + + public static final String HIERARCHY_NOT_FOUND_IN_MDMS_CODE = "HIERARCHY_NOT_FOUND_IN_MDMS"; + public static final String HIERARCHY_NOT_FOUND_IN_MDMS_MESSAGE = "Hierarchy key not found in mdms"; + + public static final String FAILED_MESSAGE = "Failed to push message to topic"; + + public static final String FACILITY_NAME_SEARCH_PARAMETER_KEY = "facilityName"; + + public static final String FACILITY_STATUS_SEARCH_PARAMETER_KEY = "facilityStatus"; + + public static final String FACILITY_TYPE_SEARCH_PARAMETER_KEY = "facilityType"; + + public static final String COMMA_DELIMITER = ","; + + public static final String SERVING_POPULATION_CODE = "servingPopulation"; + + public static final String CONFIRMED_TARGET_POPULATION_AGE_3TO11 = "CONFIRMED_HCM_ADMIN_CONSOLE_TARGET_POPULATION_AGE_3TO11"; + + public static final String CONFIRMED_TARGET_POPULATION_AGE_12TO59 = "CONFIRMED_HCM_ADMIN_CONSOLE_TARGET_POPULATION_AGE_12TO59"; + + public static final String CONFIRMED_TARGET_POPULATION = "CONFIRMED_HCM_ADMIN_CONSOLE_TARGET_POPULATION"; + } diff --git a/health-services/plan-service/src/main/java/digit/kafka/ProjectFactoryCreatePlanFacilityConsumer.java b/health-services/plan-service/src/main/java/digit/kafka/ProjectFactoryCreatePlanFacilityConsumer.java new file mode 100644 index 00000000000..f01da2db239 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/kafka/ProjectFactoryCreatePlanFacilityConsumer.java @@ -0,0 +1,57 @@ +package digit.kafka; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.repository.PlanFacilityRepository; +import digit.service.enrichment.PlanFacilityEnricher; +import digit.util.CommonUtil; +import digit.web.models.PlanFacilityRequest; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +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 org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.Map; + +import static digit.config.ServiceConstants.HIERARCHY_TYPE; + +@Slf4j +@Component +public class ProjectFactoryCreatePlanFacilityConsumer { + + private ObjectMapper objectMapper; + + private PlanFacilityEnricher enrichment; + + private CommonUtil commonUtil; + + private PlanFacilityRepository repository; + + public ProjectFactoryCreatePlanFacilityConsumer(ObjectMapper objectMapper, PlanFacilityEnricher enrichment, CommonUtil commonUtil, PlanFacilityRepository repository) { + this.objectMapper = objectMapper; + this.enrichment = enrichment; + this.commonUtil = commonUtil; + this.repository = repository; + } + + @KafkaListener(topics = {"${project.factory.save.plan.facility.consumer.topic}"}) + public void listen(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + PlanFacilityRequest planFacilityRequest = objectMapper.convertValue(consumerRecord, PlanFacilityRequest.class); + String hierarchyType = commonUtil.extractFieldsFromJsonObject(planFacilityRequest.getPlanFacility().getAdditionalDetails(), HIERARCHY_TYPE).toString(); + + if(!StringUtils.isEmpty(hierarchyType)) + enrichment.enrichJurisdictionMapping(planFacilityRequest, hierarchyType); + + if(CollectionUtils.isEmpty(planFacilityRequest.getPlanFacility().getServiceBoundaries())) + planFacilityRequest.getPlanFacility().setServiceBoundaries(new ArrayList<>()); + + repository.create(planFacilityRequest); + } catch (Exception exception) { + log.error("Error in census consumer", exception); + } + } +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/kafka/UpdatePlanConfigConsumer.java b/health-services/plan-service/src/main/java/digit/kafka/UpdatePlanConfigConsumer.java index ca72bb21058..b2a97f1d77d 100644 --- a/health-services/plan-service/src/main/java/digit/kafka/UpdatePlanConfigConsumer.java +++ b/health-services/plan-service/src/main/java/digit/kafka/UpdatePlanConfigConsumer.java @@ -28,6 +28,7 @@ public UpdatePlanConfigConsumer(PlanConfigurationService planConfigurationServic public void listen(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { PlanConfigurationRequest planConfigurationRequest = objectMapper.convertValue(consumerRecord, PlanConfigurationRequest.class); + log.info("Update plan config from resource generator."); planConfigurationService.update(planConfigurationRequest); } catch (Exception exception) { log.error("Error in update plan configuration consumer while processing topic {}: {}", topic, consumerRecord, exception); diff --git a/health-services/plan-service/src/main/java/digit/repository/PlanEmployeeAssignmentRepository.java b/health-services/plan-service/src/main/java/digit/repository/PlanEmployeeAssignmentRepository.java new file mode 100644 index 00000000000..370141a8697 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/PlanEmployeeAssignmentRepository.java @@ -0,0 +1,16 @@ +package digit.repository; + +import digit.web.models.*; + +import java.util.List; + +public interface PlanEmployeeAssignmentRepository { + + public void create(PlanEmployeeAssignmentRequest planEmployeeAssignmentRequest); + + public List search(PlanEmployeeAssignmentSearchCriteria planEmployeeAssignmentSearchCriteria); + + public void update(PlanEmployeeAssignmentRequest planEmployeeAssignmentRequest); + + public Integer count(PlanEmployeeAssignmentSearchCriteria planEmployeeAssignmentSearchCriteria); +} diff --git a/health-services/plan-service/src/main/java/digit/repository/PlanFacilityRepository.java b/health-services/plan-service/src/main/java/digit/repository/PlanFacilityRepository.java new file mode 100644 index 00000000000..ce94f569086 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/PlanFacilityRepository.java @@ -0,0 +1,15 @@ +package digit.repository; + +import digit.web.models.*; + +import java.util.List; + +public interface PlanFacilityRepository { + public void create(PlanFacilityRequest planFacilityRequest); + + public List search(PlanFacilitySearchCriteria planFacilitySearchCriteria); + + void update(PlanFacilityRequest planFacilityRequest); + + public Integer count(PlanFacilitySearchCriteria planFacilitySearchCriteria); +} diff --git a/health-services/plan-service/src/main/java/digit/repository/PlanRepository.java b/health-services/plan-service/src/main/java/digit/repository/PlanRepository.java index eb76b357701..1b8c334ed7c 100644 --- a/health-services/plan-service/src/main/java/digit/repository/PlanRepository.java +++ b/health-services/plan-service/src/main/java/digit/repository/PlanRepository.java @@ -1,10 +1,9 @@ package digit.repository; -import digit.web.models.Plan; -import digit.web.models.PlanRequest; -import digit.web.models.PlanSearchCriteria; +import digit.web.models.*; import java.util.List; +import java.util.Map; public interface PlanRepository { public void create(PlanRequest planRequest); @@ -13,4 +12,9 @@ public interface PlanRepository { public void update(PlanRequest planRequest); + public Integer count(PlanSearchCriteria planSearchCriteria); + + public Map statusCount(PlanSearchRequest planSearchRequest); + + public void bulkUpdate(BulkPlanRequest body); } diff --git a/health-services/plan-service/src/main/java/digit/repository/ServiceRequestRepository.java b/health-services/plan-service/src/main/java/digit/repository/ServiceRequestRepository.java index d09d230e4fa..5a724b5b219 100644 --- a/health-services/plan-service/src/main/java/digit/repository/ServiceRequestRepository.java +++ b/health-services/plan-service/src/main/java/digit/repository/ServiceRequestRepository.java @@ -4,8 +4,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import lombok.extern.slf4j.Slf4j; +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; @@ -35,9 +35,10 @@ public Object fetchResult(StringBuilder uri, Object request) { response = restTemplate.postForObject(uri.toString(), request, Map.class); } catch (HttpClientErrorException e) { log.error(EXTERNAL_SERVICE_EXCEPTION, e); - throw new ServiceCallException(e.getResponseBodyAsString()); + throw new CustomException(EXTERNAL_SERVICE_EXCEPTION, e.getResponseBodyAsString()); } catch (Exception e) { log.error(SEARCHER_SERVICE_EXCEPTION, e); + throw new CustomException(EXTERNAL_SERVICE_EXCEPTION, e.getMessage()); } return response; diff --git a/health-services/plan-service/src/main/java/digit/repository/impl/PlanEmployeeAssignmentImpl.java b/health-services/plan-service/src/main/java/digit/repository/impl/PlanEmployeeAssignmentImpl.java new file mode 100644 index 00000000000..bba32818812 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/impl/PlanEmployeeAssignmentImpl.java @@ -0,0 +1,121 @@ +package digit.repository.impl; + +import digit.config.Configuration; +import digit.kafka.Producer; +import digit.repository.PlanEmployeeAssignmentRepository; +import digit.repository.querybuilder.PlanEmployeeAssignmentQueryBuilder; +import digit.repository.rowmapper.PlanEmployeeAssignmentRowMapper; +import digit.web.models.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@Repository +public class PlanEmployeeAssignmentImpl implements PlanEmployeeAssignmentRepository { + + private Producer producer; + + private Configuration config; + + private PlanEmployeeAssignmentQueryBuilder queryBuilder; + + private JdbcTemplate jdbcTemplate; + + private PlanEmployeeAssignmentRowMapper rowMapper; + + public PlanEmployeeAssignmentImpl(Producer producer, Configuration config, PlanEmployeeAssignmentQueryBuilder queryBuilder, JdbcTemplate jdbcTemplate, PlanEmployeeAssignmentRowMapper rowMapper) { + this.producer = producer; + this.config = config; + this.queryBuilder = queryBuilder; + this.jdbcTemplate = jdbcTemplate; + this.rowMapper = rowMapper; + } + + /** + * Pushes a new plan employee assignment to persister kafka topic. + * + * @param planEmployeeAssignmentRequest The request containing the plan employee assignment details. + */ + @Override + public void create(PlanEmployeeAssignmentRequest planEmployeeAssignmentRequest) { + PlanEmployeeAssignmentRequestDTO requestDTO = convertToReqDTO(planEmployeeAssignmentRequest); + producer.push(config.getPlanEmployeeAssignmentCreateTopic(), requestDTO); + } + + /** + * Searches for Plan employee assignments based on provided search criteria + * + * @param searchCriteria The criteria used for searching plan employee assignments + * @return A list of Plan employee assignments that matches the search criteria + */ + @Override + public List search(PlanEmployeeAssignmentSearchCriteria searchCriteria) { + List preparedStmtList = new ArrayList<>(); + String searchQuery = queryBuilder.getPlanEmployeeAssignmentQuery(searchCriteria, preparedStmtList); + log.info("Plan Employee Assignment search query : " + searchQuery); + + List planEmployeeAssignments = jdbcTemplate.query(searchQuery, rowMapper, preparedStmtList.toArray()); + return planEmployeeAssignments; + } + + /** + * Counts the number of plan employee assignments based on the provided search criteria. + * + * @param searchCriteria The search criteria for filtering plan employee assignments. + * @return The total count of plan employee assignment matching the search criteria. + */ + @Override + public Integer count(PlanEmployeeAssignmentSearchCriteria searchCriteria) { + List preparedStmtList = new ArrayList<>(); + String query = queryBuilder.getPlanEmployeeAssignmentCountQuery(searchCriteria, preparedStmtList); + Integer count = jdbcTemplate.queryForObject(query, preparedStmtList.toArray(), Integer.class); + + return count; + } + + /** + * Pushes an updated existing plan employee assignment to persister kafka topic. + * + * @param planEmployeeAssignmentRequest The request containing the updated plan employee assignment details. + */ + @Override + public void update(PlanEmployeeAssignmentRequest planEmployeeAssignmentRequest) { + PlanEmployeeAssignmentRequestDTO requestDTO = convertToReqDTO(planEmployeeAssignmentRequest); + producer.push(config.getPlanEmployeeAssignmentUpdateTopic(), requestDTO); + } + + /** + * Converts the PlanEmployeeAssignmentRequest to a data transfer object (DTO) + * + * @param planEmployeeAssignmentRequest The request to be converted to DTO + * @return a DTO for PlanEmployeeAssignmentRequest + */ + public PlanEmployeeAssignmentRequestDTO convertToReqDTO(PlanEmployeeAssignmentRequest planEmployeeAssignmentRequest) { + PlanEmployeeAssignment planEmployeeAssignment = planEmployeeAssignmentRequest.getPlanEmployeeAssignment(); + + // Creating a new data transfer object (DTO) for PlanEmployeeAssignment + PlanEmployeeAssignmentDTO planEmployeeAssignmentDTO = PlanEmployeeAssignmentDTO.builder() + .id(planEmployeeAssignment.getId()) + .tenantId(planEmployeeAssignment.getTenantId()) + .planConfigurationId(planEmployeeAssignment.getPlanConfigurationId()) + .employeeId(planEmployeeAssignment.getEmployeeId()) + .role(planEmployeeAssignment.getRole()) + .planConfigurationName(planEmployeeAssignment.getPlanConfigurationName()) + .hierarchyLevel(planEmployeeAssignment.getHierarchyLevel()) + .jurisdiction(String.join(",", planEmployeeAssignment.getJurisdiction())) + .additionalDetails(planEmployeeAssignment.getAdditionalDetails()) + .active(planEmployeeAssignment.getActive()) + .auditDetails(planEmployeeAssignment.getAuditDetails()) + .build(); + + return PlanEmployeeAssignmentRequestDTO.builder() + .requestInfo(planEmployeeAssignmentRequest.getRequestInfo()) + .planEmployeeAssignmentDTO(planEmployeeAssignmentDTO) + .build(); + } + +} diff --git a/health-services/plan-service/src/main/java/digit/repository/impl/PlanFacilityRepositoryImpl.java b/health-services/plan-service/src/main/java/digit/repository/impl/PlanFacilityRepositoryImpl.java new file mode 100644 index 00000000000..2d3c2304bae --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/impl/PlanFacilityRepositoryImpl.java @@ -0,0 +1,150 @@ +package digit.repository.impl; + +import digit.config.Configuration; +import digit.kafka.Producer; +import digit.repository.PlanFacilityRepository; +import digit.repository.querybuilder.PlanFacilityQueryBuilder; +import digit.repository.rowmapper.PlanFacilityRowMapper; +import digit.web.models.*; +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.model.CustomException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; +import java.util.ArrayList; +import java.util.List; +import static digit.config.ServiceConstants.*; + +@Repository +@Slf4j +public class PlanFacilityRepositoryImpl implements PlanFacilityRepository { + + private Producer producer; + + private JdbcTemplate jdbcTemplate; + + private PlanFacilityQueryBuilder planFacilityQueryBuilder; + + private PlanFacilityRowMapper planFacilityRowMapper; + + private Configuration config; + + public PlanFacilityRepositoryImpl(Producer producer, JdbcTemplate jdbcTemplate, PlanFacilityQueryBuilder planFacilityQueryBuilder, PlanFacilityRowMapper planFacilityRowMapper, Configuration config) { + this.producer = producer; + this.jdbcTemplate = jdbcTemplate; + this.planFacilityQueryBuilder = planFacilityQueryBuilder; + this.planFacilityRowMapper = planFacilityRowMapper; + this.config = config; + } + + /** + * This method emits an event to the persister for it to save the plan facility linkage in the database. + * @param planFacilityRequest + */ + @Override + public void create(PlanFacilityRequest planFacilityRequest) { + // Convert the incoming PlanFacilityRequest to PlanFacilityRequestDTO + PlanFacilityRequestDTO requestDTO = convertToDTO(planFacilityRequest); + + // Push the requestDTO to the producer for processing + producer.push(config.getPlanFacilityCreateTopic(), requestDTO); + } + + public PlanFacilityRequestDTO convertToDTO(PlanFacilityRequest planFacilityRequest) { + PlanFacility planFacility = planFacilityRequest.getPlanFacility(); + + // Create a new PlanFacilityDTO + PlanFacilityDTO planFacilityDTO = PlanFacilityDTO.builder() + .id(planFacility.getId()) + .tenantId(planFacility.getTenantId()) + .planConfigurationId(planFacility.getPlanConfigurationId()) + .planConfigurationName(planFacility.getPlanConfigurationName()) + .facilityId(planFacility.getFacilityId()) + .facilityName(planFacility.getFacilityName()) + .jurisdictionMapping(planFacility.getJurisdictionMapping()) + .boundaryAncestralPath(planFacility.getBoundaryAncestralPath()) + .residingBoundary(planFacility.getResidingBoundary()) + .serviceBoundaries(convertArrayToString(planFacility.getServiceBoundaries())) + .initiallySetServiceBoundaries(planFacility.getInitiallySetServiceBoundaries()) + .additionalDetails(planFacility.getAdditionalDetails()) + .active(planFacility.getActive()) + .auditDetails(planFacility.getAuditDetails()) + .build(); + + // Return the complete PlanFacilityRequestDTO + return PlanFacilityRequestDTO.builder() + .requestInfo(planFacilityRequest.getRequestInfo()) + .planFacilityDTO(planFacilityDTO) + .build(); + } + + /** + * This is a helper function to convert an array of string to comma separated string + * + * @param stringList Array of string to be converted + * @return a string + */ + private String convertArrayToString(List stringList) { + return String.join(COMMA_DELIMITER, stringList); + } + + + + /** + * This method searches for plans based on the search criteria. + * + * @param planFacilitySearchCriteria + * @return List + */ + @Override + public List search(PlanFacilitySearchCriteria planFacilitySearchCriteria) { + // Fetch plan facility from database + return queryDatabaseForPlanFacilities(planFacilitySearchCriteria); + } + + /** + * This method emits an event to the persister for it to update the plan facility in the database. + * + * @param planFacilityRequest + */ + @Override + public void update(PlanFacilityRequest planFacilityRequest) { + try { + PlanFacilityRequestDTO requestDTO = convertToDTO(planFacilityRequest); + producer.push(config.getPlanFacilityUpdateTopic(), requestDTO); + log.info("Successfully pushed update for plan facility: {}", planFacilityRequest.getPlanFacility().getId()); + } catch (Exception e) { + throw new CustomException(FAILED_MESSAGE,config.getPlanFacilityUpdateTopic()); + } + } + + /** + * Counts the number of plan facilities based on the provided search criteria. + * + * @param planFacilitySearchCriteria The search criteria for filtering plan facilities. + * @return The total count of plan facilities matching the search criteria. + */ + @Override + public Integer count(PlanFacilitySearchCriteria planFacilitySearchCriteria) { + List preparedStmtList = new ArrayList<>(); + String query = planFacilityQueryBuilder.getPlanFacilityCountQuery(planFacilitySearchCriteria, preparedStmtList); + Integer count = jdbcTemplate.queryForObject(query, preparedStmtList.toArray(), Integer.class); + + return count; + } + + /** + * Helper method to query database for plan facilities based on the provided search criteria. + * + * @param planFacilitySearchCriteria + * @return List + */ + private List queryDatabaseForPlanFacilities(PlanFacilitySearchCriteria planFacilitySearchCriteria) { + List preparedStmtList = new ArrayList<>(); + String query = planFacilityQueryBuilder.getPlanFacilitySearchQuery(planFacilitySearchCriteria, preparedStmtList); + log.info("Plan facility search {}", query); + log.info(preparedStmtList.toString()); + return jdbcTemplate.query(query, planFacilityRowMapper, preparedStmtList.toArray()); + } + + +} diff --git a/health-services/plan-service/src/main/java/digit/repository/impl/PlanRepositoryImpl.java b/health-services/plan-service/src/main/java/digit/repository/impl/PlanRepositoryImpl.java index c6acbb55221..99e4b9487de 100644 --- a/health-services/plan-service/src/main/java/digit/repository/impl/PlanRepositoryImpl.java +++ b/health-services/plan-service/src/main/java/digit/repository/impl/PlanRepositoryImpl.java @@ -5,17 +5,21 @@ import digit.repository.PlanRepository; import digit.repository.querybuilder.PlanQueryBuilder; import digit.repository.rowmapper.PlanRowMapper; -import digit.web.models.Plan; -import digit.web.models.PlanRequest; -import digit.web.models.PlanSearchCriteria; +import digit.repository.rowmapper.PlanStatusCountRowMapper; +import digit.service.workflow.WorkflowService; +import digit.web.models.*; import lombok.extern.slf4j.Slf4j; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.SingleColumnRowMapper; import org.springframework.stereotype.Repository; import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; import java.util.ArrayList; import java.util.List; +import java.util.Map; + +import static digit.config.ServiceConstants.PLAN_ESTIMATION_BUSINESS_SERVICE; @Slf4j @Repository @@ -31,13 +35,19 @@ public class PlanRepositoryImpl implements PlanRepository { private Configuration config; + private PlanStatusCountRowMapper statusCountRowMapper; + + private WorkflowService workflowService; + public PlanRepositoryImpl(Producer producer, PlanQueryBuilder planQueryBuilder, PlanRowMapper planRowMapper, - JdbcTemplate jdbcTemplate, Configuration config) { + JdbcTemplate jdbcTemplate, Configuration config, PlanStatusCountRowMapper statusCountRowMapper, WorkflowService workflowService) { this.producer = producer; this.planQueryBuilder = planQueryBuilder; this.planRowMapper = planRowMapper; this.jdbcTemplate = jdbcTemplate; this.config = config; + this.statusCountRowMapper = statusCountRowMapper; + this.workflowService = workflowService; } /** @@ -46,11 +56,8 @@ public PlanRepositoryImpl(Producer producer, PlanQueryBuilder planQueryBuilder, */ @Override public void create(PlanRequest planRequest) { - try { - producer.push(config.getPlanCreateTopic(), planRequest); - } catch (Exception e) { - log.info("Pushing message to topic " + config.getPlanCreateTopic() + " failed.", e); - } + PlanRequestDTO planRequestDTO = convertToPlanReqDTO(planRequest); + producer.push(config.getPlanCreateTopic(), planRequestDTO); } /** @@ -70,9 +77,29 @@ public List search(PlanSearchCriteria planSearchCriteria) { } // Fetch plans from database based on the acquired ids - List plans = searchPlanByIds(planIds); + return searchPlanByIds(planIds); + } - return plans; + /** + * Counts the plan based on their current status for the provided search criteria. + * + * @param planSearchRequest The search criteria for filtering plans. + * @return The status count of plans for the given search criteria. + */ + @Override + public Map statusCount(PlanSearchRequest planSearchRequest) { + List preparedStmtList = new ArrayList<>(); + List statusList = workflowService.getStatusFromBusinessService(planSearchRequest.getRequestInfo(), PLAN_ESTIMATION_BUSINESS_SERVICE, planSearchRequest.getPlanSearchCriteria().getTenantId()); + + String query = planQueryBuilder.getPlanStatusCountQuery(planSearchRequest.getPlanSearchCriteria(), preparedStmtList); + Map statusCountMap = jdbcTemplate.query(query, statusCountRowMapper, preparedStmtList.toArray()); + + statusList.forEach(status -> { + if(ObjectUtils.isEmpty(statusCountMap.get(status))) + statusCountMap.put(status, 0); + }); + + return statusCountMap; } /** @@ -81,13 +108,41 @@ public List search(PlanSearchCriteria planSearchCriteria) { */ @Override public void update(PlanRequest planRequest) { - try { - producer.push(config.getPlanUpdateTopic(), planRequest); - } catch (Exception e) { - log.info("Pushing message to topic " + config.getPlanUpdateTopic() + " failed.", e); - } + PlanRequestDTO planRequestDTO = convertToPlanReqDTO(planRequest); + producer.push(config.getPlanUpdateTopic(), planRequestDTO); } + @Override + public void bulkUpdate(BulkPlanRequest body) { + // Get bulk plan update query + String bulkPlanUpdateQuery = planQueryBuilder.getBulkPlanQuery(); + + // Prepare rows for bulk update + List rows = body.getPlans().stream().map(plan -> new Object[] { + plan.getStatus(), + !CollectionUtils.isEmpty(plan.getAssignee()) ? String.join(",", plan.getAssignee()) : plan.getAssignee(), + plan.getAuditDetails().getLastModifiedBy(), + plan.getAuditDetails().getLastModifiedTime(), + plan.getId() + }).toList(); + + // Perform batch update + jdbcTemplate.batchUpdate(bulkPlanUpdateQuery, rows); + producer.push(config.getPlanBulkUpdateTopic(), body); + } + + /** + * Counts the number of plans based on the provided search criteria. + * @param planSearchCriteria The search criteria for filtering plans. + * @return The total count of plans matching the search criteria. + */ + @Override + public Integer count(PlanSearchCriteria planSearchCriteria) { + List preparedStmtList = new ArrayList<>(); + String query = planQueryBuilder.getPlanCountQuery(planSearchCriteria, preparedStmtList); + return jdbcTemplate.queryForObject(query, preparedStmtList.toArray(), Integer.class); + } + /** * Helper method to query database for plan ids based on the provided search criteria. * @param planSearchCriteria @@ -112,4 +167,41 @@ private List searchPlanByIds(List planIds) { return jdbcTemplate.query(query, planRowMapper, preparedStmtList.toArray()); } + /** + * Converts the PlanRequest to a data transfer object (DTO) + * + * @param planRequest The request to be converted to DTO + * @return a DTO for PlanRequest + */ + private PlanRequestDTO convertToPlanReqDTO(PlanRequest planRequest) { + Plan plan = planRequest.getPlan(); + + String assignee = !CollectionUtils.isEmpty(plan.getAssignee()) ? String.join(",", plan.getAssignee()) : null; + + // Creating a new data transfer object (DTO) for Plan + PlanDTO planDTO = PlanDTO.builder() + .id(plan.getId()) + .tenantId(plan.getTenantId()) + .locality(plan.getLocality()) + .campaignId(plan.getCampaignId()) + .planConfigurationId(plan.getPlanConfigurationId()) + .status(plan.getStatus()) + .assignee(assignee) + .additionalDetails(plan.getAdditionalDetails()) + .jurisdictionMapping(plan.getJurisdictionMapping()) + .activities(plan.getActivities()) + .resources(plan.getResources()) + .targets(plan.getTargets()) + .auditDetails(plan.getAuditDetails()) + .boundaryAncestralPath(plan.getBoundaryAncestralPath()) + .build(); + + // Returning the PlanRequestDTO + return PlanRequestDTO.builder() + .requestInfo(planRequest.getRequestInfo()) + .planDTO(planDTO) + .build(); + } + + } 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 6dc4449b55f..e8caef51d94 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 @@ -1,30 +1,35 @@ package digit.repository.querybuilder; import digit.config.Configuration; - import digit.util.QueryUtil; import digit.web.models.PlanConfigurationSearchCriteria; -import java.util.LinkedHashSet; -import java.util.List; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; +import java.util.LinkedHashSet; +import java.util.List; + +import static digit.config.ServiceConstants.PERCENTAGE_WILDCARD; + @Component public class PlanConfigQueryBuilder { private Configuration config; - public PlanConfigQueryBuilder(Configuration config) { + private QueryUtil queryUtil; + + public PlanConfigQueryBuilder(Configuration config, QueryUtil queryUtil) { this.config = config; + this.queryUtil = queryUtil; } private static final String PLAN_CONFIG_SEARCH_BASE_QUERY = "SELECT id FROM plan_configuration pc "; - private static final String PLAN_CONFIG_QUERY = "SELECT pc.id as plan_configuration_id, pc.tenant_id as plan_configuration_tenant_id, pc.name as plan_configuration_name, pc.execution_plan_id as plan_configuration_execution_plan_id, pc.status as plan_configuration_status, pc.created_by as plan_configuration_created_by, pc.created_time as plan_configuration_created_time, pc.last_modified_by as plan_configuration_last_modified_by, pc.last_modified_time as plan_configuration_last_modified_time, \n" + + private static final String PLAN_CONFIG_QUERY = "SELECT pc.id as plan_configuration_id, pc.tenant_id as plan_configuration_tenant_id, pc.name as plan_configuration_name, pc.campaign_id as plan_configuration_campaign_id, pc.status as plan_configuration_status, pc.additional_details as plan_configuration_additional_details, pc.created_by as plan_configuration_created_by, pc.created_time as plan_configuration_created_time, pc.last_modified_by as plan_configuration_last_modified_by, pc.last_modified_time as plan_configuration_last_modified_time, \n" + "\t pcf.id as plan_configuration_files_id, pcf.plan_configuration_id as plan_configuration_files_plan_configuration_id, pcf.filestore_id as plan_configuration_files_filestore_id, pcf.input_file_type as plan_configuration_files_input_file_type, pcf.template_identifier as plan_configuration_files_template_identifier, pcf.active as plan_configuration_files_active, pcf.created_by as plan_configuration_files_created_by, pcf.created_time as plan_configuration_files_created_time, pcf.last_modified_by as plan_configuration_files_last_modified_by, pcf.last_modified_time as plan_configuration_files_last_modified_time,\n" + - "\t pca.id as plan_configuration_assumptions_id, pca.key as plan_configuration_assumptions_key, pca.value as plan_configuration_assumptions_value, pca.active as plan_configuration_assumptions_active, pca.plan_configuration_id as plan_configuration_assumptions_plan_configuration_id, pca.created_by as plan_configuration_assumptions_created_by, pca.created_time as plan_configuration_assumptions_created_time, pca.last_modified_by as plan_configuration_assumptions_last_modified_by, pca.last_modified_time as plan_configuration_assumptions_last_modified_time,\n" + - "\t pco.id as plan_configuration_operations_id, pco.input as plan_configuration_operations_input, pco.operator as plan_configuration_operations_operator, pco.assumption_value as plan_configuration_operations_assumption_value, pco.output as plan_configuration_operations_output, pco.active as plan_configuration_operations_active, pco.plan_configuration_id as plan_configuration_operations_plan_configuration_id, pco.created_by as plan_configuration_operations_created_by, pco.created_time as plan_configuration_operations_created_time, pco.last_modified_by as plan_configuration_operations_last_modified_by, pco.last_modified_time as plan_configuration_operations_last_modified_time,\n" + + "\t pca.id as plan_configuration_assumptions_id, pca.key as plan_configuration_assumptions_key, pca.value as plan_configuration_assumptions_value, pca.source as plan_configuration_assumptions_source, pca.category as plan_configuration_assumptions_category, pca.active as plan_configuration_assumptions_active, pca.plan_configuration_id as plan_configuration_assumptions_plan_configuration_id, pca.created_by as plan_configuration_assumptions_created_by, pca.created_time as plan_configuration_assumptions_created_time, pca.last_modified_by as plan_configuration_assumptions_last_modified_by, pca.last_modified_time as plan_configuration_assumptions_last_modified_time,\n" + + "\t pco.id as plan_configuration_operations_id, pco.input as plan_configuration_operations_input, pco.operator as plan_configuration_operations_operator, pco.assumption_value as plan_configuration_operations_assumption_value, pco.output as plan_configuration_operations_output, pco.source as plan_configuration_operations_source, pco.category as plan_configuration_operations_category, pco.active as plan_configuration_operations_active, pco.execution_order as plan_configuration_execution_order, pco.show_on_estimation_dashboard as plan_configuration_operations_show_on_estimation_dashboard,pco.plan_configuration_id as plan_configuration_operations_plan_configuration_id, pco.created_by as plan_configuration_operations_created_by, pco.created_time as plan_configuration_operations_created_time, pco.last_modified_by as plan_configuration_operations_last_modified_by, pco.last_modified_time as plan_configuration_operations_last_modified_time,\n" + "\t pcm.id as plan_configuration_mapping_id, pcm.filestore_id as plan_configuration_mapping_filestore_id, pcm.mapped_from as plan_configuration_mapping_mapped_from, pcm.mapped_to as plan_configuration_mapping_mapped_to, pcm.active as plan_configuration_mapping_active, pcm.plan_configuration_id as plan_configuration_mapping_plan_configuration_id, pcm.created_by as plan_configuration_mapping_created_by, pcm.created_time as plan_configuration_mapping_created_time, pcm.last_modified_by as plan_configuration_mapping_last_modified_by, pcm.last_modified_time as plan_configuration_mapping_last_modified_time\n" + "\t FROM plan_configuration pc\n" + "\t LEFT JOIN plan_configuration_files pcf ON pc.id = pcf.plan_configuration_id\n" + @@ -44,14 +49,14 @@ private String buildPlanConfigQuery(List ids, List preparedStmtL StringBuilder builder = new StringBuilder(PLAN_CONFIG_QUERY); if (!CollectionUtils.isEmpty(ids)) { - QueryUtil.addClauseIfRequired(builder, preparedStmtList); - builder.append(" pc.id IN ( ").append(QueryUtil.createQuery(ids.size())).append(" )"); - QueryUtil.addToPreparedStatement(preparedStmtList, new LinkedHashSet<>(ids)); + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pc.id IN ( ").append(queryUtil.createQuery(ids.size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, ids); } addActiveWhereClause(builder, preparedStmtList); - return QueryUtil.addOrderByClause(builder.toString(), PLAN_CONFIG_SEARCH_QUERY_ORDER_BY_CLAUSE); + return queryUtil.addOrderByClause(builder.toString(), PLAN_CONFIG_SEARCH_QUERY_ORDER_BY_CLAUSE); } /** @@ -64,7 +69,7 @@ private String buildPlanConfigQuery(List ids, List preparedStmtL */ public String getPlanConfigSearchQuery(PlanConfigurationSearchCriteria criteria, List preparedStmtList) { String query = buildPlanConfigSearchQuery(criteria, preparedStmtList, Boolean.FALSE); - query = QueryUtil.addOrderByClause(query, PLAN_CONFIG_SEARCH_QUERY_ORDER_BY_CLAUSE); + query = queryUtil.addOrderByClause(query, PLAN_CONFIG_SEARCH_QUERY_ORDER_BY_CLAUSE); query = getPaginatedQuery(query, criteria, preparedStmtList); return query; @@ -97,22 +102,28 @@ private String buildPlanConfigSearchQuery(PlanConfigurationSearchCriteria criter preparedStmtList.add(criteria.getId()); } - if (criteria.getExecutionPlanId() != null) { + if (!CollectionUtils.isEmpty(criteria.getIds())) { + addClauseIfRequired(preparedStmtList, builder); + builder.append(" pc.id IN ( ").append(queryUtil.createQuery(criteria.getIds().size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, criteria.getIds()); + } + + if (criteria.getCampaignId() != null) { addClauseIfRequired(preparedStmtList, builder); - builder.append(" pc.execution_plan_id = ?"); - preparedStmtList.add(criteria.getExecutionPlanId()); + builder.append(" pc.campaign_id = ?"); + preparedStmtList.add(criteria.getCampaignId()); } if (criteria.getName() != null) { addClauseIfRequired(preparedStmtList, builder); - builder.append(" pc.name = ?"); - preparedStmtList.add(criteria.getName()); + builder.append(" pc.name ILIKE ?"); + preparedStmtList.add(PERCENTAGE_WILDCARD + criteria.getName() + PERCENTAGE_WILDCARD); } - if (criteria.getStatus() != null) { + if (!CollectionUtils.isEmpty(criteria.getStatus())) { addClauseIfRequired(preparedStmtList, builder); - builder.append(" pc.status = ?"); - preparedStmtList.add(criteria.getStatus()); + builder.append(" pc.status IN ( ").append(queryUtil.createQuery(criteria.getStatus().size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, criteria.getStatus()); } if (criteria.getUserUuid() != null) { @@ -162,22 +173,21 @@ private String getPaginatedQuery(String query, PlanConfigurationSearchCriteria p return paginatedQuery.toString(); } - public void addActiveWhereClause(StringBuilder builder, List preparedStmtList) - { + public void addActiveWhereClause(StringBuilder builder, List preparedStmtList) { addClauseIfRequired(preparedStmtList, builder); - builder.append(" pcf.active = ?"); + builder.append(" ( pcf.active = ? OR pcf.active IS NULL )"); preparedStmtList.add(Boolean.TRUE); addClauseIfRequired(preparedStmtList, builder); - builder.append(" pca.active = ?"); + builder.append(" ( pca.active = ? OR pca.active IS NULL )"); preparedStmtList.add(Boolean.TRUE); addClauseIfRequired(preparedStmtList, builder); - builder.append(" pco.active = ?"); + builder.append(" ( pco.active = ? OR pco.active IS NULL )"); preparedStmtList.add(Boolean.TRUE); addClauseIfRequired(preparedStmtList, builder); - builder.append(" pcm.active = ?"); + builder.append(" ( pcm.active = ? OR pcm.active IS NULL )"); preparedStmtList.add(Boolean.TRUE); } diff --git a/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanEmployeeAssignmentQueryBuilder.java b/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanEmployeeAssignmentQueryBuilder.java new file mode 100644 index 00000000000..b63f790f806 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanEmployeeAssignmentQueryBuilder.java @@ -0,0 +1,170 @@ +package digit.repository.querybuilder; + +import digit.config.Configuration; +import digit.util.QueryUtil; +import digit.web.models.PlanEmployeeAssignmentSearchCriteria; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; + +import static digit.config.ServiceConstants.PERCENTAGE_WILDCARD; + +@Component +public class PlanEmployeeAssignmentQueryBuilder { + + private QueryUtil queryUtil; + + private Configuration config; + + public PlanEmployeeAssignmentQueryBuilder(QueryUtil queryUtil, Configuration config) { + + this.queryUtil = queryUtil; + this.config = config; + } + + private static final String PLAN_EMPLOYEE_ASSIGNMENT_SEARCH_BASE_QUERY = "SELECT pa.id, pa.tenant_id, pa.plan_configuration_id, pa.plan_configuration_name, pa.employee_id, pa.role, pa.hierarchy_level, pa.jurisdiction, pa.additional_details, pa.active, pa.created_by, pa.created_time, pa.last_modified_by, pa.last_modified_time FROM plan_employee_assignment pa "; + + private static final String PLAN_EMPLOYEE_ASSIGNMENT_SEARCH_QUERY_ORDER_BY_CLAUSE = " ORDER BY pa.last_modified_time DESC"; + + private static final String UNIQUE_PLAN_EMPLOYEE_ASSIGNMENT_RANKED_QUERY = "WITH ranked_assignments AS ( SELECT pa.id, pa.tenant_id, pa.plan_configuration_id, pa.plan_configuration_name,pa.employee_id, pa.role, pa.hierarchy_level, pa.jurisdiction, pa.additional_details, pa.active, pa.created_by, pa.created_time, pa.last_modified_by, pa.last_modified_time, pc.last_modified_time AS pc_last_modified_time, ROW_NUMBER() OVER ( PARTITION BY pa.plan_configuration_id ORDER BY pc.last_modified_time DESC ) AS row_num FROM plan_employee_assignment pa JOIN plan_configuration pc ON pa.plan_configuration_id = pc.id "; + + private static final String UNIQUE_PLAN_EMPLOYEE_ASSIGNMENT_MAIN_SEARCH_QUERY = " SELECT id, tenant_id, plan_configuration_id, plan_configuration_name, employee_id, role, hierarchy_level, jurisdiction, additional_details, active, created_by, created_time, last_modified_by, last_modified_time FROM ranked_assignments WHERE row_num = 1 "; + + private static final String UNIQUE_PLAN_EMPLOYEE_ASSIGNMENT_SEARCH_QUERY_ORDER_BY_CLAUSE = " ORDER BY pc_last_modified_time DESC "; + + private static final String PLAN_EMPLOYEE_ASSIGNMENT_SEARCH_QUERY_COUNT_WRAPPER = "SELECT COUNT(id) AS total_count FROM ( "; + + /** + * Constructs a SQL query string for searching PlanEmployeeAssignment objects based on the provided search criteria. + * Also adds an ORDER BY clause and handles pagination. + * + * @param searchCriteria The criteria used for filtering PlanEmployeeAssignment objects. + * @param preparedStmtList A list to store prepared statement parameters. + * @return A complete SQL query string for searching PlanEmployeeAssignment objects. + */ + public String getPlanEmployeeAssignmentQuery(PlanEmployeeAssignmentSearchCriteria searchCriteria, List preparedStmtList) { + String query = buildPlanEmployeeAssignmentQuery(searchCriteria, preparedStmtList, Boolean.FALSE); + query = queryUtil.addOrderByClause(query, Boolean.TRUE.equals(searchCriteria.getFilterUniqueByPlanConfig()) ? + UNIQUE_PLAN_EMPLOYEE_ASSIGNMENT_SEARCH_QUERY_ORDER_BY_CLAUSE : PLAN_EMPLOYEE_ASSIGNMENT_SEARCH_QUERY_ORDER_BY_CLAUSE); + query = getPaginatedQuery(query, searchCriteria, preparedStmtList); + return query; + } + + /** + * Constructs the count query to get the total count of plan employee assignments based on search criteria + * + * @param searchCriteria The criteria used for filtering PlanEmployeeAssignment objects. + * @param preparedStmtList A list to store prepared statement parameters. + * @return A SQL query string to get the total count of plan employee assignments + */ + public String getPlanEmployeeAssignmentCountQuery(PlanEmployeeAssignmentSearchCriteria searchCriteria, List preparedStmtList) { + String query = buildPlanEmployeeAssignmentQuery(searchCriteria, preparedStmtList, Boolean.TRUE); + return query; + } + + /** + * Constructs query based on the provided search criteria + * + * @param searchCriteria The criteria used for filtering PlanEmployeeAssignment objects. + * @param preparedStmtList A list to store prepared statement parameters. + * @param isCount is true if count query is required for the provided search criteria + * @return A SQL query string for searching planEmployeeAssignment + */ + private String buildPlanEmployeeAssignmentQuery(PlanEmployeeAssignmentSearchCriteria searchCriteria, List preparedStmtList, Boolean isCount) { + StringBuilder builder = Boolean.TRUE.equals(searchCriteria.getFilterUniqueByPlanConfig()) ? + new StringBuilder(UNIQUE_PLAN_EMPLOYEE_ASSIGNMENT_RANKED_QUERY) : new StringBuilder(PLAN_EMPLOYEE_ASSIGNMENT_SEARCH_BASE_QUERY); + + if (searchCriteria.getId() != null) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pa.id = ?"); + preparedStmtList.add(searchCriteria.getId()); + } + + if (searchCriteria.getTenantId() != null) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pa.tenant_id = ?"); + preparedStmtList.add(searchCriteria.getTenantId()); + } + + if (searchCriteria.getPlanConfigurationId() != null) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pa.plan_configuration_id = ?"); + preparedStmtList.add(searchCriteria.getPlanConfigurationId()); + } + + if (searchCriteria.getPlanConfigurationName() != null) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pa.plan_configuration_name ILIKE ?"); + preparedStmtList.add(PERCENTAGE_WILDCARD + searchCriteria.getPlanConfigurationName() + PERCENTAGE_WILDCARD); + } + + if (!CollectionUtils.isEmpty(searchCriteria.getEmployeeId())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pa.employee_id IN ( ").append(queryUtil.createQuery(searchCriteria.getEmployeeId().size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, searchCriteria.getEmployeeId()); + } + + if (!CollectionUtils.isEmpty(searchCriteria.getPlanConfigurationStatus())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pc.status IN ( ").append(queryUtil.createQuery(searchCriteria.getPlanConfigurationStatus().size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, searchCriteria.getPlanConfigurationStatus()); + } + + if (!CollectionUtils.isEmpty(searchCriteria.getRole())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pa.role IN ( ").append(queryUtil.createQuery(searchCriteria.getRole().size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, searchCriteria.getRole()); + } + + if(searchCriteria.getHierarchyLevel() != null) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pa.hierarchy_level = ?"); + preparedStmtList.add(searchCriteria.getHierarchyLevel()); + } + + if (searchCriteria.getActive() != null) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" pa.active = ?"); + preparedStmtList.add(searchCriteria.getActive()); + } + + if (!CollectionUtils.isEmpty(searchCriteria.getJurisdiction())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" ARRAY [ ").append(queryUtil.createQuery(searchCriteria.getJurisdiction().size())).append(" ]").append("::text[] "); + builder.append(" && string_to_array(jurisdiction, ',') "); + queryUtil.addToPreparedStatement(preparedStmtList, searchCriteria.getJurisdiction()); + } + + if(searchCriteria.getFilterUniqueByPlanConfig()) { + builder.append(" )").append(UNIQUE_PLAN_EMPLOYEE_ASSIGNMENT_MAIN_SEARCH_QUERY); + } + + StringBuilder countQuery = new StringBuilder(); + if (isCount) { + countQuery.append(PLAN_EMPLOYEE_ASSIGNMENT_SEARCH_QUERY_COUNT_WRAPPER).append(builder); + countQuery.append(") AS subquery"); + + return countQuery.toString(); + } + + return builder.toString(); + } + + private String getPaginatedQuery(String query, PlanEmployeeAssignmentSearchCriteria searchCriteria, List preparedStmtList) { + StringBuilder paginatedQuery = new StringBuilder(query); + + // Append offset + paginatedQuery.append(" OFFSET ? "); + preparedStmtList.add(ObjectUtils.isEmpty(searchCriteria.getOffset()) ? config.getDefaultOffset() : searchCriteria.getOffset()); + + // Append limit + paginatedQuery.append(" LIMIT ? "); + preparedStmtList.add(ObjectUtils.isEmpty(searchCriteria.getLimit()) ? config.getDefaultLimit() : searchCriteria.getLimit()); + + return paginatedQuery.toString(); + } +} diff --git a/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanFacilityQueryBuilder.java b/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanFacilityQueryBuilder.java new file mode 100644 index 00000000000..0d475c4e577 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanFacilityQueryBuilder.java @@ -0,0 +1,154 @@ +package digit.repository.querybuilder; + +import digit.config.Configuration; +import digit.util.QueryUtil; +import digit.web.models.PlanFacilitySearchCriteria; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import static digit.config.ServiceConstants.PERCENTAGE_WILDCARD; + +@Component +public class PlanFacilityQueryBuilder { + + private Configuration config; + + private QueryUtil queryUtil; + + public PlanFacilityQueryBuilder(Configuration config, QueryUtil queryUtil) { + this.config = config; + this.queryUtil = queryUtil; + } + + private static final String PLAN_FACILITY_QUERY = + "SELECT plan_facility_linkage.id as plan_facility_id, " + + "plan_facility_linkage.tenant_id as plan_facility_tenant_id, " + + "plan_facility_linkage.plan_configuration_id as plan_facility_plan_configuration_id, " + + "plan_facility_linkage.plan_configuration_name as plan_facility_plan_configuration_name, " + + "plan_facility_linkage.facility_id as plan_facility_facility_id, " + + "plan_facility_linkage.facility_name as plan_facility_facility_name, " + + "plan_facility_linkage.boundary_ancestral_path as plan_facility_boundary_ancestral_path, " + + "plan_facility_linkage.residing_boundary as plan_facility_residing_boundary, " + + "plan_facility_linkage.service_boundaries as plan_facility_service_boundaries, " + + "plan_facility_linkage.additional_details as plan_facility_additional_details, " + + "plan_facility_linkage.created_by as plan_facility_created_by, " + + "plan_facility_linkage.created_time as plan_facility_created_time, " + + "plan_facility_linkage.last_modified_by as plan_facility_last_modified_by, " + + "plan_facility_linkage.last_modified_time as plan_facility_last_modified_time, " + + "plan_facility_linkage.active as plan_facility_active " + + "FROM plan_facility_linkage"; + + private static final String PLAN_FACILITY_SEARCH_QUERY_ORDER_BY_CLAUSE = " order by plan_facility_linkage.last_modified_time desc "; + + private static final String PLAN_FACILITY_SEARCH_QUERY_COUNT_WRAPPER = "SELECT COUNT(*) AS total_count FROM ( "; + + public String getPlanFacilitySearchQuery(PlanFacilitySearchCriteria planFacilitySearchCriteria, List preparedStmtList) { + String query = buildPlanFacilitySearchQuery(planFacilitySearchCriteria, preparedStmtList, Boolean.FALSE); + query = queryUtil.addOrderByClause(query, PLAN_FACILITY_SEARCH_QUERY_ORDER_BY_CLAUSE); + query = getPaginatedQuery(query, planFacilitySearchCriteria, preparedStmtList); + return query; + } + + /** + * Constructs the count query to get the total count of plan facilities based on search criteria. + * + * @param planFacilitySearchCriteria The criteria used for filtering PlanFacility objects. + * @param preparedStmtList A list to store prepared statement parameters. + * @return A SQL query string to get the total count of plan facilities. + */ + public String getPlanFacilityCountQuery(PlanFacilitySearchCriteria planFacilitySearchCriteria, List preparedStmtList) { + String query = buildPlanFacilitySearchQuery(planFacilitySearchCriteria, preparedStmtList, Boolean.TRUE); + return query; + } + + private String buildPlanFacilitySearchQuery(PlanFacilitySearchCriteria planFacilitySearchCriteria, List preparedStmtList, boolean isCount) { + StringBuilder builder = new StringBuilder(PLAN_FACILITY_QUERY); + + if (!CollectionUtils.isEmpty(planFacilitySearchCriteria.getIds())) { + Set ids = planFacilitySearchCriteria.getIds(); + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" id IN ( ").append(queryUtil.createQuery(ids.size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, ids); + } + + if (!ObjectUtils.isEmpty(planFacilitySearchCriteria.getTenantId())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" tenant_id = ? "); + preparedStmtList.add(planFacilitySearchCriteria.getTenantId()); + } + + if (!ObjectUtils.isEmpty(planFacilitySearchCriteria.getPlanConfigurationId())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" plan_configuration_id = ? "); + preparedStmtList.add(planFacilitySearchCriteria.getPlanConfigurationId()); + } + + if (!ObjectUtils.isEmpty(planFacilitySearchCriteria.getPlanConfigurationName())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" plan_configuration_name ILIKE ? "); + preparedStmtList.add(PERCENTAGE_WILDCARD + planFacilitySearchCriteria.getPlanConfigurationName() + PERCENTAGE_WILDCARD); + } + + if (!ObjectUtils.isEmpty(planFacilitySearchCriteria.getFacilityId())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" facility_id = ? "); + preparedStmtList.add(planFacilitySearchCriteria.getFacilityId()); + } + + if (!ObjectUtils.isEmpty(planFacilitySearchCriteria.getFacilityName())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" facility_name ILIKE ? "); + preparedStmtList.add(PERCENTAGE_WILDCARD + planFacilitySearchCriteria.getFacilityName() + PERCENTAGE_WILDCARD); + } + + if (!ObjectUtils.isEmpty(planFacilitySearchCriteria.getResidingBoundaries())) { + List residingBoundaries = planFacilitySearchCriteria.getResidingBoundaries(); + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" residing_boundary IN ( ").append(queryUtil.createQuery(residingBoundaries.size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, residingBoundaries); + } + + if (!CollectionUtils.isEmpty(planFacilitySearchCriteria.getJurisdiction())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" ARRAY [ ").append(queryUtil.createQuery(planFacilitySearchCriteria.getJurisdiction().size())).append(" ]::text[] "); + builder.append(" && string_to_array(boundary_ancestral_path, '|') "); + queryUtil.addToPreparedStatement(preparedStmtList, planFacilitySearchCriteria.getJurisdiction()); + } + + if(!CollectionUtils.isEmpty(planFacilitySearchCriteria.getFiltersMap())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" additional_details @> CAST( ? AS jsonb )"); + String partialQueryJsonString = queryUtil.preparePartialJsonStringFromFilterMap(planFacilitySearchCriteria.getFiltersMap()); + preparedStmtList.add(partialQueryJsonString); + } + + StringBuilder countQuery = new StringBuilder(); + if (isCount) { + countQuery.append(PLAN_FACILITY_SEARCH_QUERY_COUNT_WRAPPER).append(builder); + countQuery.append(") AS subquery"); + + return countQuery.toString(); + } + + return builder.toString(); + } + + private String getPaginatedQuery(String query, PlanFacilitySearchCriteria planFacilitySearchCriteria, List preparedStmtList) { + StringBuilder paginatedQuery = new StringBuilder(query); + + // Append offset + paginatedQuery.append(" OFFSET ? "); + preparedStmtList.add(ObjectUtils.isEmpty(planFacilitySearchCriteria.getOffset()) ? config.getDefaultOffset() : planFacilitySearchCriteria.getOffset()); + + // Append limit + paginatedQuery.append(" LIMIT ? "); + preparedStmtList.add(ObjectUtils.isEmpty(planFacilitySearchCriteria.getLimit()) ? config.getDefaultLimit() : planFacilitySearchCriteria.getLimit()); + + return paginatedQuery.toString(); + } + +} diff --git a/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanQueryBuilder.java b/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanQueryBuilder.java index 1b0adb59213..5c8bc91097b 100644 --- a/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanQueryBuilder.java +++ b/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanQueryBuilder.java @@ -6,6 +6,9 @@ import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; + +import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; @@ -14,13 +17,16 @@ public class PlanQueryBuilder { private Configuration config; - public PlanQueryBuilder(Configuration config) { + private QueryUtil queryUtil; + + public PlanQueryBuilder(Configuration config, QueryUtil queryUtil) { this.config = config; + this.queryUtil = queryUtil; } private static final String PLAN_SEARCH_BASE_QUERY = "SELECT id FROM plan "; - private static final String PLAN_QUERY = "SELECT plan.id as plan_id, plan.tenant_id as plan_tenant_id, plan.locality as plan_locality, plan.execution_plan_id as plan_execution_plan_id, plan.plan_configuration_id as plan_plan_configuration_id, plan.additional_details as plan_additional_details, plan.created_by as plan_created_by, plan.created_time as plan_created_time, plan.last_modified_by as plan_last_modified_by, plan.last_modified_time as plan_last_modified_time,\n" + + private static final String PLAN_QUERY = "SELECT plan.id as plan_id, plan.tenant_id as plan_tenant_id, plan.locality as plan_locality, plan.campaign_id as plan_campaign_id, plan.plan_configuration_id as plan_plan_configuration_id, plan.boundary_ancestral_path as plan_boundary_ancestral_path, plan.status as plan_status, plan.assignee as plan_assignee, plan.additional_details as plan_additional_details, plan.created_by as plan_created_by, plan.created_time as plan_created_time, plan.last_modified_by as plan_last_modified_by, plan.last_modified_time as plan_last_modified_time,\n" + "\t plan_activity.id as plan_activity_id, plan_activity.code as plan_activity_code, plan_activity.description as plan_activity_description, plan_activity.planned_start_date as plan_activity_planned_start_date, plan_activity.planned_end_date as plan_activity_planned_end_date, plan_activity.dependencies as plan_activity_dependencies, plan_activity.plan_id as plan_activity_plan_id, plan_activity.created_by as plan_activity_created_by, plan_activity.created_time as plan_activity_created_time, plan_activity.last_modified_by as plan_activity_last_modified_by, plan_activity.last_modified_time as plan_activity_last_modified_time,\n" + "\t plan_activity_condition.id as plan_activity_condition_id, plan_activity_condition.entity as plan_activity_condition_entity, plan_activity_condition.entity_property as plan_activity_condition_entity_property, plan_activity_condition.expression as plan_activity_condition_expression, plan_activity_condition.activity_id as plan_activity_condition_activity_id, plan_activity_condition.is_active as plan_activity_condition_is_active, plan_activity_condition.created_by as plan_activity_condition_created_by, plan_activity_condition.created_time as plan_activity_condition_created_time, plan_activity_condition.last_modified_by as plan_activity_condition_last_modified_by, plan_activity_condition.last_modified_time as plan_activity_condition_last_modified_time,\n" + "\t plan_resource.id as plan_resource_id, plan_resource.resource_type as plan_resource_resource_type, plan_resource.estimated_number as plan_resource_estimated_number, plan_resource.plan_id as plan_resource_plan_id, plan_resource.activity_code as plan_resource_activity_code, plan_resource.created_by as plan_resource_created_by, plan_resource.created_time as plan_resource_created_time, plan_resource.last_modified_by as plan_resource_last_modified_by, plan_resource.last_modified_time as plan_resource_last_modified_time,\n" + @@ -31,8 +37,14 @@ public PlanQueryBuilder(Configuration config) { "\t LEFT JOIN plan_resource ON plan.id = plan_resource.plan_id\n" + "\t LEFT JOIN plan_target ON plan.id = plan_target.plan_id"; + private static final String BULK_PLAN_UPDATE_QUERY = "UPDATE plan SET status = ?, assignee = ?, last_modified_by = ?, last_modified_time = ? WHERE id = ?"; + private static final String PLAN_SEARCH_QUERY_ORDER_BY_CLAUSE = " order by plan.last_modified_time desc "; + private static final String PLAN_SEARCH_QUERY_COUNT_WRAPPER = "SELECT COUNT(id) AS total_count FROM ( "; + + private static final String PLAN_STATUS_COUNT_QUERY = "SELECT COUNT(id) as plan_status_count, status FROM (SELECT id, status FROM plan {INTERNAL_QUERY}) as plan_status_map GROUP BY status"; + public String getPlanQuery(List ids, List preparedStmtList) { return buildPlanQuery(ids, preparedStmtList); } @@ -41,60 +53,137 @@ private String buildPlanQuery(List ids, List preparedStmtList) { StringBuilder builder = new StringBuilder(PLAN_QUERY); if (!CollectionUtils.isEmpty(ids)) { - QueryUtil.addClauseIfRequired(builder, preparedStmtList); - builder.append(" plan.id IN ( ").append(QueryUtil.createQuery(ids.size())).append(" )"); - QueryUtil.addToPreparedStatement(preparedStmtList, new LinkedHashSet<>(ids)); + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" plan.id IN ( ").append(queryUtil.createQuery(ids.size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, ids); } - return builder.toString(); + return queryUtil.addOrderByClause(builder.toString(), PLAN_SEARCH_QUERY_ORDER_BY_CLAUSE); } public String getPlanSearchQuery(PlanSearchCriteria planSearchCriteria, List preparedStmtList) { - String query = buildPlanSearchQuery(planSearchCriteria, preparedStmtList); - query = QueryUtil.addOrderByClause(query, PLAN_SEARCH_QUERY_ORDER_BY_CLAUSE); + String query = buildPlanSearchQuery(planSearchCriteria, preparedStmtList, Boolean.FALSE, Boolean.FALSE); + query = queryUtil.addOrderByClause(query, PLAN_SEARCH_QUERY_ORDER_BY_CLAUSE); query = getPaginatedQuery(query, planSearchCriteria, preparedStmtList); return query; } + /** + * Method to build a query to get the toatl count of plans based on the given search criteria + * + * @param criteria + * @param preparedStmtList + * @return + */ + public String getPlanCountQuery(PlanSearchCriteria criteria, List preparedStmtList) { + String query = buildPlanSearchQuery(criteria, preparedStmtList, Boolean.TRUE, Boolean.FALSE); + return query; + } + + /** + * Constructs the status count query to get the count of plans based on their current status for the given search criteria + * + * @param searchCriteria The criteria used for filtering Plans. + * @param preparedStmtList A list to store prepared statement parameters. + * @return A SQL query string to get the status count of Plans for a given search criteria. + */ + public String getPlanStatusCountQuery(PlanSearchCriteria searchCriteria, List preparedStmtList) { + PlanSearchCriteria planSearchCriteria = PlanSearchCriteria.builder() + .tenantId(searchCriteria.getTenantId()) + .planConfigurationId(searchCriteria.getPlanConfigurationId()) + .campaignId(searchCriteria.getCampaignId()) + .jurisdiction(searchCriteria.getJurisdiction()) + .build(); + return buildPlanSearchQuery(planSearchCriteria, preparedStmtList, Boolean.FALSE, Boolean.TRUE); + } + /** * Method to build query dynamically based on the criteria passed to the method + * * @param planSearchCriteria * @param preparedStmtList * @return */ - private String buildPlanSearchQuery(PlanSearchCriteria planSearchCriteria, List preparedStmtList) { + private String buildPlanSearchQuery(PlanSearchCriteria planSearchCriteria, List preparedStmtList, boolean isCount, boolean isStatusCount) { StringBuilder builder = new StringBuilder(PLAN_SEARCH_BASE_QUERY); + if(isStatusCount) { + builder = new StringBuilder(); + } + if (!ObjectUtils.isEmpty(planSearchCriteria.getTenantId())) { - QueryUtil.addClauseIfRequired(builder, preparedStmtList); + queryUtil.addClauseIfRequired(builder, preparedStmtList); builder.append(" tenant_id = ? "); preparedStmtList.add(planSearchCriteria.getTenantId()); } if (!CollectionUtils.isEmpty(planSearchCriteria.getIds())) { - QueryUtil.addClauseIfRequired(builder, preparedStmtList); - builder.append(" id IN ( ").append(QueryUtil.createQuery(planSearchCriteria.getIds().size())).append(" )"); - QueryUtil.addToPreparedStatement(preparedStmtList, planSearchCriteria.getIds()); + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" id IN ( ").append(queryUtil.createQuery(planSearchCriteria.getIds().size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, planSearchCriteria.getIds()); } - if (!ObjectUtils.isEmpty(planSearchCriteria.getLocality())) { - QueryUtil.addClauseIfRequired(builder, preparedStmtList); - builder.append(" locality = ? "); - preparedStmtList.add(planSearchCriteria.getLocality()); + if (!CollectionUtils.isEmpty(planSearchCriteria.getLocality())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" locality IN ( ").append(queryUtil.createQuery(planSearchCriteria.getLocality().size())).append(" )"); + queryUtil.addToPreparedStatement(preparedStmtList, planSearchCriteria.getLocality()); } - if (!ObjectUtils.isEmpty(planSearchCriteria.getExecutionPlanId())) { - QueryUtil.addClauseIfRequired(builder, preparedStmtList); - builder.append(" execution_plan_id = ? "); - preparedStmtList.add(planSearchCriteria.getExecutionPlanId()); + if (!ObjectUtils.isEmpty(planSearchCriteria.getCampaignId())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" campaign_id = ? "); + preparedStmtList.add(planSearchCriteria.getCampaignId()); } if (!ObjectUtils.isEmpty(planSearchCriteria.getPlanConfigurationId())) { - QueryUtil.addClauseIfRequired(builder, preparedStmtList); + queryUtil.addClauseIfRequired(builder, preparedStmtList); builder.append(" plan_configuration_id = ? "); preparedStmtList.add(planSearchCriteria.getPlanConfigurationId()); } + if (!ObjectUtils.isEmpty(planSearchCriteria.getStatus())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" status = ? "); + preparedStmtList.add(planSearchCriteria.getStatus()); + } + + if (!ObjectUtils.isEmpty(planSearchCriteria.getAssignee())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" assignee = ? "); + preparedStmtList.add(planSearchCriteria.getAssignee()); + } + + if (!ObjectUtils.isEmpty(planSearchCriteria.getAssignee())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" ARRAY [ ").append(queryUtil.createQuery(Collections.singleton(planSearchCriteria.getAssignee()).size())).append(" ]").append("::text[] "); + builder.append(" && string_to_array(assignee, ',') "); + queryUtil.addToPreparedStatement(preparedStmtList, Collections.singleton(planSearchCriteria.getAssignee())); + } + + if (!CollectionUtils.isEmpty(planSearchCriteria.getJurisdiction())) { + queryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" ARRAY [ ") + .append(queryUtil.createQuery(planSearchCriteria.getJurisdiction().size())) + .append(" ]::text[] "); + + builder.append(" && string_to_array(boundary_ancestral_path, '|') "); + queryUtil.addToPreparedStatement(preparedStmtList, planSearchCriteria.getJurisdiction()); + } + + + StringBuilder countQuery = new StringBuilder(); + if (isCount) { + + countQuery.append(PLAN_SEARCH_QUERY_COUNT_WRAPPER).append(builder); + countQuery.append(") AS subquery"); + + return countQuery.toString(); + } + + if (isStatusCount) { + return PLAN_STATUS_COUNT_QUERY.replace("{INTERNAL_QUERY}", builder); + } + return builder.toString(); } @@ -112,4 +201,7 @@ private String getPaginatedQuery(String query, PlanSearchCriteria planSearchCrit return paginatedQuery.toString(); } + public String getBulkPlanQuery() { + return BULK_PLAN_UPDATE_QUERY; + } } diff --git a/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanConfigRowMapper.java b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanConfigRowMapper.java index f8aebd12a9a..4645ce10b5e 100644 --- a/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanConfigRowMapper.java +++ b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanConfigRowMapper.java @@ -1,33 +1,35 @@ package digit.repository.rowmapper; -import digit.web.models.Assumption; -import digit.web.models.File; -import digit.web.models.Operation; -import digit.web.models.PlanConfiguration; -import digit.web.models.ResourceMapping; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import digit.util.QueryUtil; +import digit.web.models.*; import org.egov.common.contract.models.AuditDetails; +import org.postgresql.util.PGobject; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; + @Component public class PlanConfigRowMapper implements ResultSetExtractor> { + private QueryUtil queryUtil; + + public PlanConfigRowMapper(QueryUtil queryUtil) { + this.queryUtil = queryUtil; + } + @Override public List extractData(ResultSet rs) throws SQLException, DataAccessException { Map planConfigurationMap = new LinkedHashMap<>(); - Map fileMap = new LinkedHashMap<>(); - Map operationMap = new LinkedHashMap<>(); - Map assumptionMap = new LinkedHashMap<>(); - Map resourceMappingMap = new LinkedHashMap<>(); + Set fileSet = new HashSet<>(); + Set operationSet = new HashSet<>(); + Set assumptionSet = new HashSet<>(); + Set resourceMappingSet = new HashSet<>(); while (rs.next()) { @@ -37,6 +39,10 @@ public List extractData(ResultSet rs) throws SQLException, Da if (ObjectUtils.isEmpty(planConfigEntry)) { planConfigEntry = new PlanConfiguration(); + fileSet.clear(); + operationSet.clear(); + assumptionSet.clear(); + resourceMappingSet.clear(); // Prepare audit details AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("plan_configuration_created_by")).createdTime(rs.getLong("plan_configuration_created_time")).lastModifiedBy(rs.getString("plan_configuration_last_modified_by")).lastModifiedTime(rs.getLong("plan_configuration_last_modified_time")).build(); @@ -45,15 +51,16 @@ public List extractData(ResultSet rs) throws SQLException, Da planConfigEntry.setId(planConfigId); planConfigEntry.setTenantId(rs.getString("plan_configuration_tenant_id")); planConfigEntry.setName(rs.getString("plan_configuration_name")); - planConfigEntry.setExecutionPlanId(rs.getString("plan_configuration_execution_plan_id")); - planConfigEntry.setStatus(PlanConfiguration.StatusEnum.valueOf(rs.getString("plan_configuration_status").toUpperCase())); + planConfigEntry.setCampaignId(rs.getString("plan_configuration_campaign_id")); + planConfigEntry.setStatus(rs.getString("plan_configuration_status")); + planConfigEntry.setAdditionalDetails(queryUtil.getAdditionalDetail((PGobject) rs.getObject("plan_configuration_additional_details"))); planConfigEntry.setAuditDetails(auditDetails); } - addFiles(rs, planConfigEntry, fileMap); - addAssumptions(rs, planConfigEntry, assumptionMap); - addOperations(rs, planConfigEntry, operationMap); - addResourceMappings(rs, planConfigEntry, resourceMappingMap); + addFiles(rs, planConfigEntry, fileSet); + addAssumptions(rs, planConfigEntry, assumptionSet); + addOperations(rs, planConfigEntry, operationSet); + addResourceMappings(rs, planConfigEntry, resourceMappingSet); planConfigurationMap.put(planConfigId, planConfigEntry); } @@ -65,13 +72,13 @@ public List extractData(ResultSet rs) throws SQLException, Da * * @param rs The ResultSet containing the data. * @param planConfigEntry The PlanConfiguration entry to which the File object will be added. - * @param fileMap A map to keep track of added File objects. + * @param fileSet A set to keep track of added File objects. * @throws SQLException If an SQL error occurs. */ - private void addFiles(ResultSet rs, PlanConfiguration planConfigEntry, Map fileMap) throws SQLException { + private void addFiles(ResultSet rs, PlanConfiguration planConfigEntry, Set fileSet) throws SQLException { String fileId = rs.getString("plan_configuration_files_id"); - if (ObjectUtils.isEmpty(fileId) || fileMap.containsKey(fileId)) { + if (ObjectUtils.isEmpty(fileId) || fileSet.contains(fileId)) { return; } @@ -89,7 +96,7 @@ private void addFiles(ResultSet rs, PlanConfiguration planConfigEntry, Map assumptionMap) throws SQLException { + private void addAssumptions(ResultSet rs, PlanConfiguration planConfigEntry, Set assumptionSet) throws SQLException { String assumptionId = rs.getString("plan_configuration_assumptions_id"); - if (ObjectUtils.isEmpty(assumptionId) || assumptionMap.containsKey(assumptionId)) { + if (ObjectUtils.isEmpty(assumptionId) || assumptionSet.contains(assumptionId)) { return; } @@ -113,6 +120,8 @@ private void addAssumptions(ResultSet rs, PlanConfiguration planConfigEntry, Map assumption.setKey(rs.getString("plan_configuration_assumptions_key")); assumption.setValue(rs.getBigDecimal("plan_configuration_assumptions_value")); assumption.setActive(rs.getBoolean("plan_configuration_assumptions_active")); + assumption.setSource(Source.valueOf(rs.getString("plan_configuration_assumptions_source"))); + assumption.setCategory(rs.getString("plan_configuration_assumptions_category")); if (CollectionUtils.isEmpty(planConfigEntry.getAssumptions())) { List assumptionList = new ArrayList<>(); @@ -122,7 +131,7 @@ private void addAssumptions(ResultSet rs, PlanConfiguration planConfigEntry, Map planConfigEntry.getAssumptions().add(assumption); } - assumptionMap.put(assumptionId, assumption); + assumptionSet.add(assumptionId); } /** @@ -130,13 +139,13 @@ private void addAssumptions(ResultSet rs, PlanConfiguration planConfigEntry, Map * * @param rs The ResultSet containing the data. * @param planConfigEntry The PlanConfiguration entry to which the Operation object will be added. - * @param operationMap A map to keep track of added Operation objects. + * @param operationSet A set to keep track of added Operation objects. * @throws SQLException If an SQL error occurs. */ - private void addOperations(ResultSet rs, PlanConfiguration planConfigEntry, Map operationMap) throws SQLException { + private void addOperations(ResultSet rs, PlanConfiguration planConfigEntry, Set operationSet) throws SQLException { String operationId = rs.getString("plan_configuration_operations_id"); - if (ObjectUtils.isEmpty(operationId) || operationMap.containsKey(operationId)) { + if (ObjectUtils.isEmpty(operationId) || operationSet.contains(operationId)) { return; } @@ -147,6 +156,10 @@ private void addOperations(ResultSet rs, PlanConfiguration planConfigEntry, Map< operation.setAssumptionValue(rs.getString("plan_configuration_operations_assumption_value")); operation.setOutput(rs.getString("plan_configuration_operations_output")); operation.setActive(rs.getBoolean("plan_configuration_operations_active")); + operation.setShowOnEstimationDashboard(rs.getBoolean("plan_configuration_operations_show_on_estimation_dashboard")); + operation.setSource(Source.valueOf(rs.getString("plan_configuration_operations_source"))); + operation.setCategory(rs.getString("plan_configuration_operations_category")); + operation.setExecutionOrder(rs.getInt("plan_configuration_execution_order")); if (CollectionUtils.isEmpty(planConfigEntry.getOperations())) { List operationList = new ArrayList<>(); @@ -156,7 +169,7 @@ private void addOperations(ResultSet rs, PlanConfiguration planConfigEntry, Map< planConfigEntry.getOperations().add(operation); } - operationMap.put(operationId, operation); + operationSet.add(operationId); } /** @@ -164,13 +177,13 @@ private void addOperations(ResultSet rs, PlanConfiguration planConfigEntry, Map< * * @param rs The ResultSet containing the data. * @param planConfigEntry The PlanConfiguration entry to which the ResourceMapping object will be added. - * @param mappingMap A map to keep track of added ResourceMapping objects. + * @param resourceMappingSet A set to keep track of added ResourceMapping objects. * @throws SQLException If an SQL error occurs. */ - private void addResourceMappings(ResultSet rs, PlanConfiguration planConfigEntry, Map mappingMap) throws SQLException { + private void addResourceMappings(ResultSet rs, PlanConfiguration planConfigEntry, Set resourceMappingSet) throws SQLException { String mappingId = rs.getString("plan_configuration_mapping_id"); - if (ObjectUtils.isEmpty(mappingId) || mappingMap.containsKey(mappingId)) { + if (ObjectUtils.isEmpty(mappingId) || resourceMappingSet.contains(mappingId)) { return; } @@ -189,7 +202,7 @@ private void addResourceMappings(ResultSet rs, PlanConfiguration planConfigEntry planConfigEntry.getResourceMapping().add(mapping); } - mappingMap.put(mappingId, mapping); + resourceMappingSet.add(mappingId); } } diff --git a/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanEmployeeAssignmentRowMapper.java b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanEmployeeAssignmentRowMapper.java new file mode 100644 index 00000000000..edf79b72c02 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanEmployeeAssignmentRowMapper.java @@ -0,0 +1,66 @@ +package digit.repository.rowmapper; + +import digit.util.QueryUtil; +import digit.web.models.PlanEmployeeAssignment; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.models.AuditDetails; +import org.postgresql.util.PGobject; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; +import java.util.stream.Collectors; + +@Slf4j +@Component +public class PlanEmployeeAssignmentRowMapper implements ResultSetExtractor> { + + private QueryUtil queryUtil; + + public PlanEmployeeAssignmentRowMapper(QueryUtil queryUtil) { + this.queryUtil = queryUtil; + } + + @Override + public List extractData(ResultSet rs) throws SQLException, DataAccessException { + Map planEmployeeAssignmentMap = new LinkedHashMap<>(); + + while (rs.next()) { + String planEmployeeAssignmentId = rs.getString("id"); + + PlanEmployeeAssignment planEmployeeAssignment = planEmployeeAssignmentMap.get(planEmployeeAssignmentId); + + if (ObjectUtils.isEmpty(planEmployeeAssignment)) { + planEmployeeAssignment = new PlanEmployeeAssignment(); + + // Prepare audit details + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("created_by")).createdTime(rs.getLong("created_time")).lastModifiedBy(rs.getString("last_modified_by")).lastModifiedTime(rs.getLong("last_modified_time")).build(); + + // Converting jurisdiction from comma separated string to a list of string + String jurisdiction = rs.getString("jurisdiction"); + Set jurisdictionList = Arrays.stream(jurisdiction.split(",")).collect(Collectors.toSet()); + + // Prepare PlanEmployeeAssignment object + planEmployeeAssignment.setId(planEmployeeAssignmentId); + planEmployeeAssignment.setTenantId(rs.getString("tenant_id")); + planEmployeeAssignment.setPlanConfigurationId(rs.getString("plan_configuration_id")); + planEmployeeAssignment.setPlanConfigurationName(rs.getString("plan_configuration_name")); + planEmployeeAssignment.setEmployeeId(rs.getString("employee_id")); + planEmployeeAssignment.setRole(rs.getString("role")); + planEmployeeAssignment.setHierarchyLevel(rs.getString("hierarchy_level")); + planEmployeeAssignment.setJurisdiction(jurisdictionList); + planEmployeeAssignment.setActive(rs.getBoolean("active")); + planEmployeeAssignment.setAdditionalDetails(queryUtil.getAdditionalDetail((PGobject) rs.getObject("additional_details"))); + planEmployeeAssignment.setAuditDetails(auditDetails); + + planEmployeeAssignmentMap.put(planEmployeeAssignmentId, planEmployeeAssignment); + } + } + + return new ArrayList<>(planEmployeeAssignmentMap.values()); + } +} diff --git a/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanFacilityRowMapper.java b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanFacilityRowMapper.java new file mode 100644 index 00000000000..c7ea2667ef1 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanFacilityRowMapper.java @@ -0,0 +1,79 @@ +package digit.repository.rowmapper; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.web.models.PlanFacility; +import org.egov.common.contract.models.AuditDetails; +import org.egov.tracer.model.CustomException; +import org.postgresql.util.PGobject; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; +import java.io.IOException; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; + +@Component +public class PlanFacilityRowMapper implements ResultSetExtractor> { + + private final ObjectMapper objectMapper; + + public PlanFacilityRowMapper(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + @Override + public List extractData(ResultSet rs) throws SQLException, DataAccessException { + Map planFacilityMap = new LinkedHashMap<>(); + while (rs.next()) { + String planFacilityId = rs.getString("plan_facility_id"); + + PlanFacility planFacilityEntry = planFacilityMap.get(planFacilityId); + if (planFacilityEntry == null || ObjectUtils.isEmpty(planFacilityEntry)) { + planFacilityEntry = new PlanFacility(); + + // Prepare audit details + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(rs.getString("plan_facility_created_by")) + .createdTime(rs.getLong("plan_facility_created_time")) + .lastModifiedBy(rs.getString("plan_facility_last_modified_by")) + .lastModifiedTime(rs.getLong("plan_facility_last_modified_time")) + .build(); + + // Prepare plan facility object + planFacilityEntry.setId(planFacilityId); + planFacilityEntry.setTenantId(rs.getString("plan_facility_tenant_id")); + planFacilityEntry.setPlanConfigurationId(rs.getString("plan_facility_plan_configuration_id")); + planFacilityEntry.setPlanConfigurationName(rs.getString("plan_facility_plan_configuration_name")); + planFacilityEntry.setFacilityId(rs.getString("plan_facility_facility_id")); + planFacilityEntry.setFacilityName(rs.getString("plan_facility_facility_name")); + planFacilityEntry.setResidingBoundary(rs.getString("plan_facility_residing_boundary")); + planFacilityEntry.setBoundaryAncestralPath(rs.getString("plan_facility_boundary_ancestral_path")); + String serviceBoundaries = rs.getString("plan_facility_service_boundaries"); + planFacilityEntry.setServiceBoundaries(ObjectUtils.isEmpty(serviceBoundaries) ? new ArrayList<>() : Arrays.asList(serviceBoundaries.split(","))); + planFacilityEntry.setAdditionalDetails(getAdditionalDetail((PGobject) rs.getObject("plan_facility_additional_details"))); + planFacilityEntry.setAuditDetails(auditDetails); + planFacilityEntry.setActive(rs.getBoolean("plan_facility_active")); + } + + planFacilityMap.put(planFacilityId, planFacilityEntry); + } + return new ArrayList<>(planFacilityMap.values()); + } + + private JsonNode getAdditionalDetail(PGobject pGobject) { + JsonNode additionalDetail = null; + + try { + if (!ObjectUtils.isEmpty(pGobject)) { + additionalDetail = objectMapper.readTree(pGobject.getValue()); + } + } catch (IOException e) { + throw new CustomException("PARSING_ERROR", "Failed to parse additionalDetails object"); + } + + return additionalDetail; + } +} diff --git a/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanRowMapper.java b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanRowMapper.java index a82919fed46..aa00207a741 100644 --- a/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanRowMapper.java +++ b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanRowMapper.java @@ -1,10 +1,8 @@ package digit.repository.rowmapper; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; +import digit.util.QueryUtil; import digit.web.models.*; import org.egov.common.contract.models.AuditDetails; -import org.egov.tracer.model.CustomException; import org.postgresql.util.PGobject; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.ResultSetExtractor; @@ -12,7 +10,6 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; -import java.io.IOException; import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; @@ -20,28 +17,32 @@ @Component public class PlanRowMapper implements ResultSetExtractor> { - private ObjectMapper objectMapper; + private QueryUtil queryUtil; - public PlanRowMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; + public PlanRowMapper(QueryUtil queryUtil) { + this.queryUtil = queryUtil; } @Override public List extractData(ResultSet rs) throws SQLException, DataAccessException { Map planMap = new LinkedHashMap<>(); Map activityMap = new LinkedHashMap<>(); - Map conditionMap = new LinkedHashMap<>(); - Map resourceMap = new LinkedHashMap<>(); - Map targetMap = new LinkedHashMap<>(); + Set conditionSet = new HashSet<>(); + Set resourceSet = new HashSet<>(); + Set targetSet = new HashSet<>(); // Traverse through result set and create plan objects - while(rs.next()) { + while (rs.next()) { String planId = rs.getString("plan_id"); Plan planEntry = planMap.get(planId); - if(ObjectUtils.isEmpty(planEntry)) { + if (ObjectUtils.isEmpty(planEntry)) { planEntry = new Plan(); + activityMap.clear(); + conditionSet.clear(); + resourceSet.clear(); + targetSet.clear(); // Prepare audit details AuditDetails auditDetails = AuditDetails.builder() @@ -51,20 +52,26 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessExcep .lastModifiedTime(rs.getLong("plan_last_modified_time")) .build(); + String commaSeparatedAssignee = rs.getString("plan_assignee"); + List assignee = !ObjectUtils.isEmpty(commaSeparatedAssignee) ? Arrays.asList(commaSeparatedAssignee.split(",")) : null; + // Prepare plan object planEntry.setId(planId); planEntry.setTenantId(rs.getString("plan_tenant_id")); planEntry.setLocality(rs.getString("plan_locality")); - planEntry.setExecutionPlanId(rs.getString("plan_execution_plan_id")); + planEntry.setCampaignId(rs.getString("plan_campaign_id")); + planEntry.setStatus(rs.getString("plan_status")); + planEntry.setAssignee(assignee); planEntry.setPlanConfigurationId(rs.getString("plan_plan_configuration_id")); - planEntry.setAdditionalDetails(getAdditionalDetail((PGobject) rs.getObject("plan_additional_details"))); + planEntry.setBoundaryAncestralPath(rs.getString("plan_boundary_ancestral_path")); + planEntry.setAdditionalDetails(queryUtil.getAdditionalDetail((PGobject) rs.getObject("plan_additional_details"))); planEntry.setAuditDetails(auditDetails); } - addActivities(rs, planEntry, activityMap, conditionMap); - addResources(rs, planEntry, resourceMap); - addTargets(rs, planEntry, targetMap); + addActivities(rs, planEntry, activityMap, conditionSet); + addResources(rs, planEntry, resourceSet); + addTargets(rs, planEntry, targetSet); planMap.put(planId, planEntry); } @@ -72,15 +79,14 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessExcep } private void addActivities(ResultSet rs, Plan plan, - Map activityMap, Map conditionMap) throws SQLException, DataAccessException { + Map activityMap, Set conditionSet) throws SQLException, DataAccessException { String activityId = rs.getString("plan_activity_id"); - if(!ObjectUtils.isEmpty(activityId) && activityMap.containsKey(activityId)) { - addActivityConditions(rs, activityMap.get(activityId), conditionMap); + if (!ObjectUtils.isEmpty(activityId) && activityMap.containsKey(activityId)) { + addActivityConditions(rs, activityMap.get(activityId), conditionSet); return; - } - else if (ObjectUtils.isEmpty(activityId)) { + } else if (ObjectUtils.isEmpty(activityId)) { // Set activities list to empty if no activity found plan.setActivities(new ArrayList<>()); return; @@ -103,7 +109,7 @@ else if (ObjectUtils.isEmpty(activityId)) { .dependencies(ObjectUtils.isEmpty(dependencies) ? new ArrayList<>() : Arrays.asList(rs.getString("plan_activity_dependencies").split(","))) .build(); - addActivityConditions(rs, activity, conditionMap); + addActivityConditions(rs, activity, conditionSet); if (CollectionUtils.isEmpty(plan.getActivities())) { List activityList = new ArrayList<>(); @@ -117,10 +123,10 @@ else if (ObjectUtils.isEmpty(activityId)) { } - private void addActivityConditions(ResultSet rs, Activity activity, Map conditionMap) throws SQLException, DataAccessException { + private void addActivityConditions(ResultSet rs, Activity activity, Set conditionSet) throws SQLException, DataAccessException { String conditionId = rs.getString("plan_activity_condition_id"); - if(ObjectUtils.isEmpty(conditionId) || conditionMap.containsKey(conditionId)) { + if (ObjectUtils.isEmpty(conditionId) || conditionSet.contains(conditionId)) { List conditionList = new ArrayList<>(); activity.setConditions(conditionList); return; @@ -140,7 +146,7 @@ private void addActivityConditions(ResultSet rs, Activity activity, Map conditionList = new ArrayList<>(); conditionList.add(condition); activity.setConditions(conditionList); @@ -148,15 +154,15 @@ private void addActivityConditions(ResultSet rs, Activity activity, Map resourceMap) throws SQLException, DataAccessException { + private void addResources(ResultSet rs, Plan planEntry, Set resourceSet) throws SQLException, DataAccessException { String resourceId = rs.getString("plan_resource_id"); - if(ObjectUtils.isEmpty(resourceId) || resourceMap.containsKey(resourceId)) { + if (ObjectUtils.isEmpty(resourceId) || resourceSet.contains(resourceId)) { List resourceList = new ArrayList<>(); planEntry.setResources(resourceList); return; @@ -184,14 +190,14 @@ private void addResources(ResultSet rs, Plan planEntry, Map re planEntry.getResources().add(resource); } - resourceMap.put(resource.getId(), resource); + resourceSet.add(resource.getId()); } - private void addTargets(ResultSet rs, Plan planEntry, Map targetMap) throws SQLException, DataAccessException { + private void addTargets(ResultSet rs, Plan planEntry, Set targetSet) throws SQLException, DataAccessException { String targetId = rs.getString("plan_target_id"); - if(ObjectUtils.isEmpty(targetId) || targetMap.containsKey(targetId)) { + if (ObjectUtils.isEmpty(targetId) || targetSet.contains(targetId)) { List targetList = new ArrayList<>(); planEntry.setTargets(targetList); return; @@ -225,23 +231,7 @@ private void addTargets(ResultSet rs, Plan planEntry, Map target planEntry.getTargets().add(target); } - targetMap.put(target.getId(), target); - - } - - private JsonNode getAdditionalDetail(PGobject pGobject){ - JsonNode additionalDetail = null; + targetSet.add(target.getId()); - try { - if(ObjectUtils.isEmpty(pGobject)){ - additionalDetail = objectMapper.readTree(pGobject.getValue()); - } - } - catch (IOException e){ - throw new CustomException("PARSING_ERROR", "Failed to parse additionalDetails object"); - } - - return additionalDetail; } - } diff --git a/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanStatusCountRowMapper.java b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanStatusCountRowMapper.java new file mode 100644 index 00000000000..11e14d37763 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanStatusCountRowMapper.java @@ -0,0 +1,31 @@ +package digit.repository.rowmapper; + +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +@Component +public class PlanStatusCountRowMapper implements ResultSetExtractor> { + + @Override + public Map extractData(ResultSet rs) throws SQLException, DataAccessException { + + Map statusCountMap = new HashMap<>(); + + while (rs.next()) { + String status = rs.getString("status"); + Integer statusCount = rs.getInt("plan_status_count"); + + if(!ObjectUtils.isEmpty(status)) + statusCountMap.put(status, statusCount); + } + + return statusCountMap; + } +} diff --git a/health-services/plan-service/src/main/java/digit/service/PlanConfigurationService.java b/health-services/plan-service/src/main/java/digit/service/PlanConfigurationService.java index 85238f723a5..c9602b1a543 100644 --- a/health-services/plan-service/src/main/java/digit/service/PlanConfigurationService.java +++ b/health-services/plan-service/src/main/java/digit/service/PlanConfigurationService.java @@ -1,48 +1,54 @@ package digit.service; -import digit.config.Configuration; -import digit.kafka.Producer; import digit.repository.PlanConfigurationRepository; -import digit.repository.impl.PlanConfigurationRepositoryImpl; import digit.service.enrichment.EnrichmentService; import digit.service.validator.PlanConfigurationValidator; +import digit.service.validator.WorkflowValidator; +import digit.service.workflow.WorkflowService; +import digit.util.CommonUtil; import digit.util.ResponseInfoFactory; +import digit.web.models.PlanConfiguration; import digit.web.models.PlanConfigurationRequest; import digit.web.models.PlanConfigurationResponse; import digit.web.models.PlanConfigurationSearchRequest; -import java.util.Collections; import lombok.extern.slf4j.Slf4j; import org.egov.common.utils.ResponseInfoUtil; import org.springframework.stereotype.Service; +import java.util.Collections; +import java.util.List; + @Service @Slf4j public class PlanConfigurationService { - private Producer producer; - private EnrichmentService enrichmentService; - private Configuration config; - private PlanConfigurationValidator validator; private PlanConfigurationRepository repository; private ResponseInfoFactory responseInfoFactory; - public PlanConfigurationService(Producer producer, EnrichmentService enrichmentService, Configuration config - , PlanConfigurationValidator validator, PlanConfigurationRepository repository, ResponseInfoFactory responseInfoFactory) { - this.producer = producer; + private WorkflowValidator workflowValidator; + + private WorkflowService workflowService; + + private CommonUtil commonUtil; + + public PlanConfigurationService(EnrichmentService enrichmentService, PlanConfigurationValidator validator, PlanConfigurationRepository repository, ResponseInfoFactory responseInfoFactory, WorkflowService workflowService, WorkflowValidator workflowValidator, CommonUtil commonUtil) { this.enrichmentService = enrichmentService; - this.config = config; this.validator = validator; this.repository = repository; this.responseInfoFactory = responseInfoFactory; + this.workflowService = workflowService; + this.workflowValidator = workflowValidator; + this.commonUtil = commonUtil; } /** * Creates a new plan configuration based on the provided request. + * * @param request The request containing the plan configuration details. * @return The created plan configuration request. */ @@ -51,41 +57,43 @@ public PlanConfigurationResponse create(PlanConfigurationRequest request) { validator.validateCreate(request); enrichmentService.enrichCreate(request); repository.create(request); - PlanConfigurationResponse response = PlanConfigurationResponse.builder() + + return PlanConfigurationResponse.builder() .planConfiguration(Collections.singletonList(request.getPlanConfiguration())) - .responseInfo(responseInfoFactory - .createResponseInfoFromRequestInfo(request.getRequestInfo(), true)) + .responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(request.getRequestInfo(), true)) .build(); - return response; } /** * Searches for plan configurations based on the provided search criteria. + * * @param request The search request containing the criteria. * @return A list of plan configurations that match the search criteria. */ public PlanConfigurationResponse search(PlanConfigurationSearchRequest request) { validator.validateSearchRequest(request); - PlanConfigurationResponse response = PlanConfigurationResponse.builder(). + List planConfigurations = repository.search(request.getPlanConfigurationSearchCriteria()); + commonUtil.sortOperationsByExecutionOrder(planConfigurations); + return PlanConfigurationResponse.builder(). responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(request.getRequestInfo(), true)) - .planConfiguration(repository.search(request.getPlanConfigurationSearchCriteria())) + .planConfiguration(planConfigurations) .totalCount(repository.count(request.getPlanConfigurationSearchCriteria())) .build(); - - return response; } /** * Updates an existing plan configuration based on the provided request. + * * @param request The request containing the updated plan configuration details. * @return The response containing the updated plan configuration. */ public PlanConfigurationResponse update(PlanConfigurationRequest request) { validator.validateUpdateRequest(request); enrichmentService.enrichUpdate(request); + workflowValidator.validateWorkflow(request); + workflowService.invokeWorkflowForStatusUpdate(request); repository.update(request); - // Build and return response back to controller return PlanConfigurationResponse.builder() .responseInfo(ResponseInfoUtil.createResponseInfoFromRequestInfo(request.getRequestInfo(), Boolean.TRUE)) .planConfiguration(Collections.singletonList(request.getPlanConfiguration())) diff --git a/health-services/plan-service/src/main/java/digit/service/PlanEmployeeService.java b/health-services/plan-service/src/main/java/digit/service/PlanEmployeeService.java new file mode 100644 index 00000000000..afa9ee46f38 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/PlanEmployeeService.java @@ -0,0 +1,91 @@ +package digit.service; + +import digit.config.Configuration; +import digit.kafka.Producer; +import digit.repository.PlanEmployeeAssignmentRepository; +import digit.service.enrichment.PlanEmployeeAssignmentEnricher; +import digit.service.validator.PlanEmployeeAssignmentValidator; +import digit.util.ResponseInfoFactory; +import digit.web.models.*; +import org.egov.common.utils.ResponseInfoUtil; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; + +@Service +public class PlanEmployeeService { + + Producer producer; + + Configuration config; + + ResponseInfoFactory responseInfoFactory; + + PlanEmployeeAssignmentRepository repository; + + PlanEmployeeAssignmentEnricher enricher; + + PlanEmployeeAssignmentValidator validator; + + public PlanEmployeeService(Producer producer, Configuration config, ResponseInfoFactory responseInfoFactory, PlanEmployeeAssignmentRepository repository, PlanEmployeeAssignmentEnricher enricher, PlanEmployeeAssignmentValidator validator) { + this.producer = producer; + this.config = config; + this.responseInfoFactory = responseInfoFactory; + this.repository = repository; + this.enricher = enricher; + this.validator = validator; + } + + /** + * Creates a new plan employee assignment based on the provided request. + * + * @param request The request containing the plan employee assignment details. + * @return The response containing the created plan employee assignment. + */ + public PlanEmployeeAssignmentResponse create(PlanEmployeeAssignmentRequest request) { + validator.validateCreate(request); + enricher.enrichCreate(request); + repository.create(request); + + return PlanEmployeeAssignmentResponse.builder() + .planEmployeeAssignment(Collections.singletonList(request.getPlanEmployeeAssignment())) + .responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(request.getRequestInfo(), Boolean.TRUE)) + .build(); + } + + /** + * Searches for plan employee assignment based on the provided search criteria. + * + * @param request The search request containing the criteria. + * @return A list of plan employee assignments that matches the search criteria. + */ + public PlanEmployeeAssignmentResponse search(PlanEmployeeAssignmentSearchRequest request) { + // Delegate search request to repository + List planEmployeeAssignmentList = repository.search(request.getPlanEmployeeAssignmentSearchCriteria()); + + // Build and return response back to controller + return PlanEmployeeAssignmentResponse.builder() + .responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(request.getRequestInfo(), Boolean.TRUE)) + .planEmployeeAssignment(planEmployeeAssignmentList) + .totalCount(repository.count(request.getPlanEmployeeAssignmentSearchCriteria())) + .build(); + } + + /** + * Updates an existing plan employee assignment based on the provided request. + * + * @param request The request containing the updated plan employee assignment details. + * @return The response containing the updated plan employee assignment. + */ + public PlanEmployeeAssignmentResponse update(PlanEmployeeAssignmentRequest request) { + validator.validateUpdate(request); + enricher.enrichUpdate(request); + repository.update(request); + + return PlanEmployeeAssignmentResponse.builder() + .responseInfo(ResponseInfoUtil.createResponseInfoFromRequestInfo(request.getRequestInfo(), Boolean.TRUE)) + .planEmployeeAssignment(Collections.singletonList(request.getPlanEmployeeAssignment())) + .build(); + } +} diff --git a/health-services/plan-service/src/main/java/digit/service/PlanEnricher.java b/health-services/plan-service/src/main/java/digit/service/PlanEnricher.java index 75d79c840a3..b01c78ea82a 100644 --- a/health-services/plan-service/src/main/java/digit/service/PlanEnricher.java +++ b/health-services/plan-service/src/main/java/digit/service/PlanEnricher.java @@ -1,16 +1,18 @@ package digit.service; +import digit.web.models.Plan; import digit.web.models.PlanRequest; +import digit.web.models.boundary.BoundaryTypeHierarchy; +import digit.web.models.boundary.BoundaryTypeHierarchyDefinition; +import digit.web.models.boundary.EnrichedBoundary; +import digit.web.models.boundary.HierarchyRelation; import org.egov.common.utils.AuditDetailsEnrichmentUtil; import org.egov.common.utils.UUIDEnrichmentUtil; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; @Component public class PlanEnricher { @@ -105,5 +107,125 @@ public void enrichPlanUpdate(PlanRequest body) { } }); + // Enriching last modified time for update + body.getPlan().getAuditDetails().setLastModifiedTime(System.currentTimeMillis()); + } + + /** + * Enriches the boundary ancestral path and jurisdiction mapping for the provided boundary code in the plan request. + * + * @param plan The plan record whose boundary ancestral path has to be enriched. + * @param tenantBoundary boundary relationship from the boundary service for the given boundary code. + */ + public void enrichBoundaryAncestralPath(Plan plan, HierarchyRelation tenantBoundary) { + EnrichedBoundary boundary = tenantBoundary.getBoundary().get(0); + Map jurisdictionMapping = new LinkedHashMap<>(); + + StringBuilder boundaryAncestralPath = new StringBuilder(boundary.getCode()); + jurisdictionMapping.put(boundary.getBoundaryType(), boundary.getCode()); + + // Iterate through the child boundary until there are no more + while (!CollectionUtils.isEmpty(boundary.getChildren())) { + boundary = boundary.getChildren().get(0); + boundaryAncestralPath.append("|").append(boundary.getCode()); + jurisdictionMapping.put(boundary.getBoundaryType(), boundary.getCode()); + } + + // Setting the boundary ancestral path for the provided boundary + plan.setBoundaryAncestralPath(boundaryAncestralPath.toString()); + + // Setting jurisdiction mapping for the provided boundary + plan.setJurisdictionMapping(jurisdictionMapping); + } + + /** + * Helper method to enrich boundary hierarchy mapping. + * Creates a mapping of parentBoundaryType to childBoundaryType from the boundaryTypeHierarchy search response. + * + * @param boundaryTypeHierarchyDef Search response from boundary hierarchy search. + * @param boundaryHierarchyMapping boundary hierarchy map to be enriched. + * @return returns the highest boundary hierarchy for the given hierarchy type. + */ + private String getBoundaryHierarchyMapping(BoundaryTypeHierarchyDefinition boundaryTypeHierarchyDef, Map boundaryHierarchyMapping) { + String highestBoundaryHierarchy = null; + + for (BoundaryTypeHierarchy boundaryTypeHierarchy : boundaryTypeHierarchyDef.getBoundaryHierarchy()) { + if (ObjectUtils.isEmpty(boundaryTypeHierarchy.getParentBoundaryType())) + highestBoundaryHierarchy = boundaryTypeHierarchy.getBoundaryType(); + else + boundaryHierarchyMapping.put(boundaryTypeHierarchy.getParentBoundaryType(), boundaryTypeHierarchy.getBoundaryType()); + } + + return highestBoundaryHierarchy; + } + + /** + * Enriches jurisdiction mapping in plan for the given boundary ancestral path. + * + * @param plan plan with boundary ancestral path. + * @param boundaryTypeHierarchyDef boundary hierarchy for the given hierarchy type. + */ + public void enrichJurisdictionMapping(Plan plan, BoundaryTypeHierarchyDefinition boundaryTypeHierarchyDef) { + Map boundaryHierarchyMapping = new HashMap<>(); + + // Enriches the boundaryHierarchyMapping and returns the highest boundary hierarchy for the given hierarchy type. + String highestBoundaryHierarchy = getBoundaryHierarchyMapping(boundaryTypeHierarchyDef, boundaryHierarchyMapping); + + Map jurisdictionMapping = new LinkedHashMap<>(); + String boundaryHierarchy = highestBoundaryHierarchy; + + // Get the list of boundary codes from pipe separated boundaryAncestralPath. + List boundaryCode = getBoundaryCodeFromAncestralPath(plan.getBoundaryAncestralPath()); + + // Creates the mapping of boundary hierarchy with the corresponding boundary code. + for (String boundary : boundaryCode) { + jurisdictionMapping.put(boundaryHierarchy, boundary); + boundaryHierarchy = boundaryHierarchyMapping.get(boundaryHierarchy); + } + + plan.setJurisdictionMapping(jurisdictionMapping); + } + + /** + * Enriches jurisdiction mapping for the list of plans for the given boundary ancestral path. + * + * @param planList list of plans with boundary ancestral paths. + * @param boundaryTypeHierarchyDef boundary hierarchy for the given hierarchy type. + */ + public void enrichJurisdictionMapping(List planList, BoundaryTypeHierarchyDefinition boundaryTypeHierarchyDef) { + Map boundaryHierarchyMapping = new HashMap<>(); + + // Enriches the boundaryHierarchyMapping and returns the highest boundary hierarchy for the given hierarchy type. + String highestBoundaryHierarchy = getBoundaryHierarchyMapping(boundaryTypeHierarchyDef, boundaryHierarchyMapping); + + for (Plan plan : planList) { + + Map jurisdictionMapping = new LinkedHashMap<>(); + String boundaryHierarchy = highestBoundaryHierarchy; + + // Get the list of boundary codes from pipe separated boundaryAncestralPath. + List boundaryCode = getBoundaryCodeFromAncestralPath(plan.getBoundaryAncestralPath()); + + // Creates the mapping of boundary hierarchy with the corresponding boundary code. + for (String boundary : boundaryCode) { + jurisdictionMapping.put(boundaryHierarchy, boundary); + boundaryHierarchy = boundaryHierarchyMapping.get(boundaryHierarchy); + } + + plan.setJurisdictionMapping(jurisdictionMapping); + } + } + + /** + * Converts the boundaryAncestral path from a pipe separated string to an array of boundary codes. + * + * @param boundaryAncestralPath pipe separated boundaryAncestralPath. + * @return a list of boundary codes. + */ + private List getBoundaryCodeFromAncestralPath(String boundaryAncestralPath) { + if (ObjectUtils.isEmpty(boundaryAncestralPath)) { + return Collections.emptyList(); + } + return Arrays.asList(boundaryAncestralPath.split("\\|")); } } diff --git a/health-services/plan-service/src/main/java/digit/service/PlanFacilityService.java b/health-services/plan-service/src/main/java/digit/service/PlanFacilityService.java new file mode 100644 index 00000000000..8282a0fea74 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/PlanFacilityService.java @@ -0,0 +1,98 @@ +package digit.service; + +import digit.repository.PlanFacilityRepository; +import digit.service.enrichment.PlanFacilityEnricher; +import digit.service.validator.PlanFacilityValidator; +import digit.util.ResponseInfoFactory; +import digit.web.models.PlanFacility; +import digit.web.models.PlanFacilityRequest; +import digit.web.models.PlanFacilityResponse; +import org.egov.common.utils.ResponseInfoUtil; +import digit.web.models.PlanFacilitySearchRequest; +import org.springframework.stereotype.Service; +import java.util.Collections; +import java.util.List; + +@Service +public class PlanFacilityService { + + private PlanFacilityValidator planFacilityValidator; + private ResponseInfoFactory responseInfoFactory; + private PlanFacilityEnricher planFacilityEnricher; + private PlanFacilityRepository planFacilityRepository; + + public PlanFacilityService(PlanFacilityValidator planFacilityValidator, ResponseInfoFactory responseInfoFactory, PlanFacilityEnricher planFacilityEnricher, PlanFacilityRepository planFacilityRepository) { + this.planFacilityValidator = planFacilityValidator; + this.responseInfoFactory = responseInfoFactory; + this.planFacilityEnricher = planFacilityEnricher; + this.planFacilityRepository = planFacilityRepository; + } + + /** + * This method processes the requests that come for creating plan facilities. + * + * @param planFacilityRequest The PlanFacilityRequest containing the plan facility details for creation. + * @return PlanFacilityResponse containing the created plan facility and response information. + */ + public PlanFacilityResponse createPlanFacility(PlanFacilityRequest planFacilityRequest) { + // Validate plan facility create request + planFacilityValidator.validatePlanFacilityCreate(planFacilityRequest); + + // Enrich plan facility create request + planFacilityEnricher.enrichPlanFacilityCreate(planFacilityRequest); + + // Delegate creation request to repository + planFacilityRepository.create(planFacilityRequest); + + // Build and return response back to controller + return PlanFacilityResponse.builder() + .planFacility(Collections.singletonList(planFacilityRequest.getPlanFacility())) + .responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(planFacilityRequest.getRequestInfo(), Boolean.TRUE)) + .build(); + } + + /** + * This method processes the requests that come for searching plan facilities. + * + * @param planFacilitySearchRequest containing the search criteria and request information. + * @return PlanFacilityResponse object containing the search results and response information. + */ + public PlanFacilityResponse searchPlanFacility(PlanFacilitySearchRequest planFacilitySearchRequest) { + // Enrich search request + planFacilityEnricher.enrichSearchRequest(planFacilitySearchRequest); + + // Delegate request to repository + List planFacilityList = planFacilityRepository.search(planFacilitySearchRequest.getPlanFacilitySearchCriteria()); + + // Build and return response back to controller + return PlanFacilityResponse.builder() + .responseInfo(ResponseInfoUtil.createResponseInfoFromRequestInfo(planFacilitySearchRequest.getRequestInfo(), Boolean.TRUE)) + .planFacility(planFacilityList) + .totalCount(planFacilityRepository.count(planFacilitySearchRequest.getPlanFacilitySearchCriteria())) + .build(); + } + + /** + * Processes requests for updating plan facilities. + * + * @param planFacilityRequest The PlanFacilityRequest containing the update information. + * @return PlanFacilityResponse containing the updated plan facility and response information. + */ + public PlanFacilityResponse updatePlanFacility(PlanFacilityRequest planFacilityRequest) { + //validate plan facility request + planFacilityValidator.validatePlanFacilityUpdate(planFacilityRequest); + + //enrich plan facility request + planFacilityEnricher.enrichPlanFacilityUpdate(planFacilityRequest); + + //delegate update request to repository + planFacilityRepository.update(planFacilityRequest); + + //Build and return response back to controller + return PlanFacilityResponse.builder(). + responseInfo(ResponseInfoUtil.createResponseInfoFromRequestInfo(planFacilityRequest.getRequestInfo(), Boolean.TRUE)). + planFacility(Collections.singletonList(planFacilityRequest.getPlanFacility())). + build(); + } + +} diff --git a/health-services/plan-service/src/main/java/digit/service/PlanService.java b/health-services/plan-service/src/main/java/digit/service/PlanService.java index c0c97a30eaf..4acaf58218b 100644 --- a/health-services/plan-service/src/main/java/digit/service/PlanService.java +++ b/health-services/plan-service/src/main/java/digit/service/PlanService.java @@ -1,16 +1,16 @@ package digit.service; import digit.repository.PlanRepository; -import digit.web.models.Plan; -import digit.web.models.PlanRequest; -import digit.web.models.PlanResponse; -import digit.web.models.PlanSearchRequest; +import digit.service.workflow.WorkflowService; +import digit.web.models.*; +import org.egov.common.contract.response.ResponseInfo; import org.egov.common.utils.ResponseInfoUtil; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; @Service public class PlanService { @@ -21,10 +21,13 @@ public class PlanService { private PlanRepository planRepository; - public PlanService(PlanValidator planValidator, PlanEnricher planEnricher, PlanRepository planRepository) { + private WorkflowService workflowService; + + public PlanService(PlanValidator planValidator, PlanEnricher planEnricher, PlanRepository planRepository, WorkflowService workflowService) { this.planValidator = planValidator; this.planEnricher = planEnricher; this.planRepository = planRepository; + this.workflowService = workflowService; } /** @@ -39,6 +42,9 @@ public PlanResponse createPlan(PlanRequest body) { // Enrich plan create request planEnricher.enrichPlanCreate(body); + // Call workflow transition API for status update + workflowService.invokeWorkflowForStatusUpdate(body); + // Delegate creation request to repository planRepository.create(body); @@ -58,10 +64,18 @@ public PlanResponse searchPlan(PlanSearchRequest body) { // Delegate search request to repository List planList = planRepository.search(body.getPlanSearchCriteria()); + // Get the total count of plans for given search criteria + Integer count = planRepository.count(body.getPlanSearchCriteria()); + + // Get the status count of plans for given search criteria + Map statusCountMap = planRepository.statusCount(body); + // Build and return response back to controller return PlanResponse.builder() .responseInfo(ResponseInfoUtil.createResponseInfoFromRequestInfo(body.getRequestInfo(), Boolean.TRUE)) .plan(planList) + .totalCount(count) + .statusCount(statusCountMap) .build(); } @@ -77,6 +91,9 @@ public PlanResponse updatePlan(PlanRequest body) { // Enrich plan update request planEnricher.enrichPlanUpdate(body); + // Call workflow transition API for status update + workflowService.invokeWorkflowForStatusUpdate(body); + // Delegate update request to repository planRepository.update(body); @@ -86,4 +103,25 @@ public PlanResponse updatePlan(PlanRequest body) { .plan(Collections.singletonList(body.getPlan())) .build(); } + + /** + * This method processes bulk update requests for plan. + * @param bulkPlanRequest + * @return + */ + public PlanResponse bulkUpdate(BulkPlanRequest bulkPlanRequest) { + // Validate bulk plan update request + planValidator.validateBulkPlanUpdate(bulkPlanRequest); + + // Call workflow transition for updating status and assignee + workflowService.invokeWorkflowForStatusUpdate(bulkPlanRequest); + + // Delegate bulk update request to repository + planRepository.bulkUpdate(bulkPlanRequest); + + // Build and return response back to controller + return PlanResponse.builder().responseInfo(ResponseInfoUtil.createResponseInfoFromRequestInfo(bulkPlanRequest.getRequestInfo(), Boolean.TRUE)) + .plan(bulkPlanRequest.getPlans()) + .build(); + } } 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 40958a9e0d3..aa1656c00b3 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 @@ -1,10 +1,18 @@ package digit.service; import com.jayway.jsonpath.JsonPath; +import digit.config.Configuration; import digit.repository.PlanConfigurationRepository; import digit.repository.PlanRepository; +import digit.util.BoundaryUtil; +import digit.util.CampaignUtil; +import digit.util.CommonUtil; import digit.util.MdmsUtil; import digit.web.models.*; +import digit.web.models.boundary.BoundarySearchResponse; +import digit.web.models.boundary.BoundaryTypeHierarchyResponse; +import digit.web.models.boundary.HierarchyRelation; +import digit.web.models.projectFactory.CampaignResponse; import org.egov.common.utils.MultiStateInstanceUtil; import org.egov.tracer.model.CustomException; import org.springframework.stereotype.Component; @@ -27,20 +35,47 @@ public class PlanValidator { private MultiStateInstanceUtil centralInstanceUtil; - public PlanValidator(PlanRepository planRepository, PlanConfigurationRepository planConfigurationRepository, MdmsUtil mdmsUtil, MultiStateInstanceUtil centralInstanceUtil) { + private CommonUtil commonUtil; + + private CampaignUtil campaignUtil; + + private PlanEmployeeService planEmployeeService; + + private Configuration config; + + private PlanEnricher planEnricher; + + private BoundaryUtil boundaryUtil; + + public PlanValidator(PlanRepository planRepository, PlanConfigurationRepository planConfigurationRepository, MdmsUtil mdmsUtil, MultiStateInstanceUtil centralInstanceUtil, CommonUtil commonUtil, CampaignUtil campaignUtil, PlanEmployeeService planEmployeeService, Configuration config, PlanEnricher planEnricher, BoundaryUtil boundaryUtil) { this.planRepository = planRepository; this.planConfigurationRepository = planConfigurationRepository; this.mdmsUtil = mdmsUtil; this.centralInstanceUtil = centralInstanceUtil; + this.commonUtil = commonUtil; + this.campaignUtil = campaignUtil; + this.planEmployeeService = planEmployeeService; + this.config = config; + this.planEnricher = planEnricher; + this.boundaryUtil = boundaryUtil; } /** * This method performs business validations on plan create requests + * * @param request */ public void validatePlanCreate(PlanRequest request) { String rootTenantId = centralInstanceUtil.getStateLevelTenant(request.getPlan().getTenantId()); Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), rootTenantId); + CampaignResponse campaignResponse = campaignUtil.fetchCampaignData(request.getRequestInfo(), request.getPlan().getCampaignId(), rootTenantId); + BoundarySearchResponse boundarySearchResponse = boundaryUtil.fetchBoundaryData(request.getRequestInfo(), request.getPlan().getLocality(), request.getPlan().getTenantId(), campaignResponse.getCampaignDetails().get(0).getHierarchyType(), Boolean.TRUE, Boolean.FALSE); + + //TODO: remove after setting the flag in consumer + request.getPlan().setRequestFromResourceEstimationConsumer(Boolean.TRUE); + + // Validate locality against boundary service + validateBoundaryCode(boundarySearchResponse, request.getPlan()); // Validate activities validateActivities(request); @@ -65,10 +100,32 @@ public void validatePlanCreate(PlanRequest request) { // Validate Metric Detail's Unit against MDMS validateMetricDetailUnit(request, mdmsData); + + // Validate if campaign id exists against project factory + validateCampaignId(campaignResponse); + + // Validate the user information in the request + commonUtil.validateUserInfo(request.getRequestInfo()); + + // Validate plan-employee assignment and jurisdiction is request is from Resource Estimation Consumer + if(!request.getPlan().isRequestFromResourceEstimationConsumer()) + validatePlanEmployeeAssignmentAndJurisdiction(request); + } + + /** + * Validates campaign ID from request against project factory + * + * @param campaignResponse The campaign details response from project factory + */ + private void validateCampaignId(CampaignResponse campaignResponse) { + if (CollectionUtils.isEmpty(campaignResponse.getCampaignDetails())) { + throw new CustomException(NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_CODE, NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_MESSAGE); + } } /** * This validation method validates if the dependent activities are valid and if they form a cycle + * * @param request */ private void validateActivityDependencies(PlanRequest request) { @@ -81,6 +138,7 @@ private void validateActivityDependencies(PlanRequest request) { /** * This method checks if the activity dependencies form a cycle + * * @param request */ private void checkForCycleInActivityDependencies(PlanRequest request) { @@ -90,7 +148,7 @@ private void checkForCycleInActivityDependencies(PlanRequest request) { activityCodeVsDependenciesMap.keySet().forEach(activityCode -> { activityCodeVsDependenciesMap.get(activityCode).forEach(dependency -> { - if(activityCodeVsDependenciesMap.get(dependency).contains(activityCode)) + if (activityCodeVsDependenciesMap.get(dependency).contains(activityCode)) throw new CustomException(CYCLIC_ACTIVITY_DEPENDENCY_CODE, CYCLIC_ACTIVITY_DEPENDENCY_MESSAGE); }); }); @@ -98,6 +156,7 @@ private void checkForCycleInActivityDependencies(PlanRequest request) { /** * This method validates if the dependent activity codes are valid + * * @param request */ private void validateDependentActivityCodes(PlanRequest request) { @@ -108,9 +167,9 @@ private void validateDependentActivityCodes(PlanRequest request) { // Check if the dependent activity codes are valid request.getPlan().getActivities().forEach(activity -> { - if(!CollectionUtils.isEmpty(activity.getDependencies())) { + if (!CollectionUtils.isEmpty(activity.getDependencies())) { activity.getDependencies().forEach(dependency -> { - if(!activityCodes.contains(dependency)) + if (!activityCodes.contains(dependency)) throw new CustomException(INVALID_ACTIVITY_DEPENDENCY_CODE, INVALID_ACTIVITY_DEPENDENCY_MESSAGE); }); } @@ -120,11 +179,12 @@ private void validateDependentActivityCodes(PlanRequest request) { /** * This method validates the activities provided in the request + * * @param request */ private void validateActivities(PlanRequest request) { // Collect all activity codes - if(request.getPlan().getActivities() == null) + if (request.getPlan().getActivities() == null) throw new CustomException(ACTIVITIES_CANNOT_BE_NULL_CODE, ACTIVITIES_CANNOT_BE_NULL_MESSAGE); Set activityCodes = request.getPlan().getActivities().stream() @@ -132,26 +192,26 @@ private void validateActivities(PlanRequest request) { .collect(Collectors.toSet()); // If activity codes are not unique, throw an exception - if(activityCodes.size() != request.getPlan().getActivities().size()) { + if (activityCodes.size() != request.getPlan().getActivities().size()) { throw new CustomException(DUPLICATE_ACTIVITY_CODES, DUPLICATE_ACTIVITY_CODES_MESSAGE); } // If execution plan id is not provided, providing activities is mandatory - if(ObjectUtils.isEmpty(request.getPlan().getExecutionPlanId()) + if (ObjectUtils.isEmpty(request.getPlan().getCampaignId()) && CollectionUtils.isEmpty(request.getPlan().getActivities())) { throw new CustomException(PLAN_ACTIVITIES_MANDATORY_CODE, PLAN_ACTIVITIES_MANDATORY_MESSAGE); } // If execution plan id is provided, providing activities is not allowed - if(!ObjectUtils.isEmpty(request.getPlan().getExecutionPlanId()) + if (!ObjectUtils.isEmpty(request.getPlan().getCampaignId()) && !CollectionUtils.isEmpty(request.getPlan().getActivities())) { throw new CustomException(PLAN_ACTIVITIES_NOT_ALLOWED_CODE, PLAN_ACTIVITIES_NOT_ALLOWED_MESSAGE); } // Validate activity dates - if(!CollectionUtils.isEmpty(request.getPlan().getActivities())) { + if (!CollectionUtils.isEmpty(request.getPlan().getActivities())) { request.getPlan().getActivities().forEach(activity -> { - if(activity.getPlannedEndDate() < activity.getPlannedStartDate()) + if (activity.getPlannedEndDate() < activity.getPlannedStartDate()) throw new CustomException(INVALID_ACTIVITY_DATES_CODE, INVALID_ACTIVITY_DATES_MESSAGE); }); } @@ -159,49 +219,37 @@ private void validateActivities(PlanRequest request) { /** * This method validates if the plan configuration id provided in the request exists + * * @param request */ private void validatePlanConfigurationExistence(PlanRequest request) { // If plan id provided is invalid, throw an exception - if(!ObjectUtils.isEmpty(request.getPlan().getPlanConfigurationId()) && CollectionUtils.isEmpty(planConfigurationRepository.search(PlanConfigurationSearchCriteria.builder() - .id(request.getPlan().getPlanConfigurationId()) - .tenantId(request.getPlan().getTenantId()) - .build()))) { + if (!ObjectUtils.isEmpty(request.getPlan().getPlanConfigurationId()) && + CollectionUtils.isEmpty(commonUtil.searchPlanConfigId(request.getPlan().getPlanConfigurationId(), request.getPlan().getTenantId()))) { throw new CustomException(INVALID_PLAN_CONFIG_ID_CODE, INVALID_PLAN_CONFIG_ID_MESSAGE); } } /** * This method validates the resources provided in the request + * * @param request */ private void validateResources(PlanRequest request) { // If plan configuration id is not provided, providing resources is mandatory - if(ObjectUtils.isEmpty(request.getPlan().getPlanConfigurationId()) + if (ObjectUtils.isEmpty(request.getPlan().getPlanConfigurationId()) && CollectionUtils.isEmpty(request.getPlan().getResources())) { throw new CustomException(PLAN_RESOURCES_MANDATORY_CODE, PLAN_RESOURCES_MANDATORY_MESSAGE); } - - // If plan configuration id is provided, providing resources is not allowed - if(!ObjectUtils.isEmpty(request.getPlan().getPlanConfigurationId()) - && !CollectionUtils.isEmpty(request.getPlan().getResources())) { - throw new CustomException(PLAN_RESOURCES_NOT_ALLOWED_CODE, PLAN_RESOURCES_NOT_ALLOWED_MESSAGE); - } - - // Validate resource type existence - if(!CollectionUtils.isEmpty(request.getPlan().getResources())) { - request.getPlan().getResources().forEach(resource -> { - // Validate resource type existence - }); - } } /** * This method validates the linkage between resources and activities + * * @param request */ private void validateResourceActivityLinkage(PlanRequest request) { - if(ObjectUtils.isEmpty(request.getPlan().getPlanConfigurationId()) + if (ObjectUtils.isEmpty(request.getPlan().getPlanConfigurationId()) && !CollectionUtils.isEmpty(request.getPlan().getActivities())) { // Collect all activity codes Set activityCodes = request.getPlan().getActivities().stream() @@ -210,7 +258,7 @@ private void validateResourceActivityLinkage(PlanRequest request) { // Validate resource-activity linkage request.getPlan().getResources().forEach(resource -> { - if(!activityCodes.contains(resource.getActivityCode())) + if (!activityCodes.contains(resource.getActivityCode())) throw new CustomException(INVALID_RESOURCE_ACTIVITY_LINKAGE_CODE, INVALID_RESOURCE_ACTIVITY_LINKAGE_MESSAGE); }); } @@ -218,10 +266,11 @@ private void validateResourceActivityLinkage(PlanRequest request) { /** * This method validates the linkage between targets and activities + * * @param request */ private void validateTargetActivityLinkage(PlanRequest request) { - if(!CollectionUtils.isEmpty(request.getPlan().getActivities())) { + if (!CollectionUtils.isEmpty(request.getPlan().getActivities())) { // Collect all activity codes Set activityCodes = request.getPlan().getActivities().stream() .map(Activity::getCode) @@ -229,7 +278,7 @@ private void validateTargetActivityLinkage(PlanRequest request) { // Validate target-activity linkage request.getPlan().getTargets().forEach(target -> { - if(!activityCodes.contains(target.getActivityCode())) + if (!activityCodes.contains(target.getActivityCode())) throw new CustomException(INVALID_TARGET_ACTIVITY_LINKAGE_CODE, INVALID_TARGET_ACTIVITY_LINKAGE_MESSAGE); }); } @@ -237,6 +286,7 @@ private void validateTargetActivityLinkage(PlanRequest request) { /** * This method performs business validations on plan update requests + * * @param request */ public void validatePlanUpdate(PlanRequest request) { @@ -245,6 +295,12 @@ public void validatePlanUpdate(PlanRequest request) { String rootTenantId = centralInstanceUtil.getStateLevelTenant(request.getPlan().getTenantId()); Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), rootTenantId); + CampaignResponse campaignResponse = campaignUtil.fetchCampaignData(request.getRequestInfo(), request.getPlan().getCampaignId(), rootTenantId); + BoundaryTypeHierarchyResponse boundaryTypeHierarchyResponse = boundaryUtil.fetchBoundaryHierarchy(request.getRequestInfo(), request.getPlan().getTenantId(), campaignResponse.getCampaignDetails().get(0).getHierarchyType()); + + //TODO: remove after setting the flag in consumer + request.getPlan().setRequestFromResourceEstimationConsumer(Boolean.TRUE); + // Validate activities validateActivities(request); @@ -279,6 +335,14 @@ public void validatePlanUpdate(PlanRequest request) { // Validate Metric Detail's Unit against MDMS validateMetricDetailUnit(request, mdmsData); + // Validate the user information in the request + commonUtil.validateUserInfo(request.getRequestInfo()); + + // Validate plan-employee assignment and jurisdiction + validatePlanEmployeeAssignmentAndJurisdiction(request); + + // Enrich jurisdiction mapping in plan + planEnricher.enrichJurisdictionMapping(request.getPlan(), boundaryTypeHierarchyResponse.getBoundaryHierarchy().get(0)); } /** @@ -338,15 +402,19 @@ private void validateActivitiesUuidUniqueness(PlanRequest request) { /** * This method validates if the plan id provided in the update request exists - * @param request + * + * @param request the PlanRequest containing the plan */ private void validatePlanExistence(PlanRequest request) { // If plan id provided is invalid, throw an exception - if(CollectionUtils.isEmpty(planRepository.search(PlanSearchCriteria.builder() + List planFromDatabase = planRepository.search(PlanSearchCriteria.builder() .ids(Collections.singleton(request.getPlan().getId())) - .build()))) { + .build()); + if (CollectionUtils.isEmpty(planFromDatabase)) { throw new CustomException(INVALID_PLAN_ID_CODE, INVALID_PLAN_ID_MESSAGE); } + // enriching boundary ancestral path for incoming plan request from the database + request.getPlan().setBoundaryAncestralPath(planFromDatabase.get(0).getBoundaryAncestralPath()); } /** @@ -355,7 +423,7 @@ private void validatePlanExistence(PlanRequest request) { * This method checks each target metric in the plan to ensure it exists in the MDMS data. * If a metric is not found, it throws a CustomException. * - * @param request the PlanRequest containing the plan and target metrics to be validated + * @param request the PlanRequest containing the plan and target metrics to be validated * @param mdmsData the MDMS data against which the target metrics are validated * @throws CustomException if there is an error reading the MDMS data using JsonPath * or if any target metric is not found in the MDMS data @@ -386,7 +454,7 @@ public void validateTargetMetrics(PlanRequest request, Object mdmsData) { * This method extracts metric details from the plan and checks if each metric unit * is present in the MDMS data. If a metric unit is not found, it throws a CustomException. * - * @param request the PlanRequest containing the plan and metric details to be validated + * @param request the PlanRequest containing the plan and metric details to be validated * @param mdmsData the MDMS data against which the metric units are validated * @throws CustomException if there is an error reading the MDMS data using JsonPath * or if any metric unit is not found in the MDMS data @@ -415,4 +483,192 @@ public void validateMetricDetailUnit(PlanRequest request, Object mdmsData) { } -} + /** + * Validates the plan's employee assignment and ensures the jurisdiction is valid based on tenant, employee, role, and plan configuration. + * If no assignment is found, throws a custom exception. + * + * @param planRequest the request containing the plan and workflow details + * @throws CustomException if no employee assignment is found or jurisdiction is invalid + */ + public void validatePlanEmployeeAssignmentAndJurisdiction(PlanRequest planRequest) { + PlanEmployeeAssignmentSearchCriteria planEmployeeAssignmentSearchCriteria = PlanEmployeeAssignmentSearchCriteria + .builder() + .tenantId(planRequest.getPlan().getTenantId()) + .employeeId(Collections.singletonList(planRequest.getRequestInfo().getUserInfo().getUuid())) + .planConfigurationId(planRequest.getPlan().getPlanConfigurationId()) + .role(config.getPlanEstimationApproverRoles()) + .build(); + + PlanEmployeeAssignmentResponse planEmployeeAssignmentResponse = planEmployeeService.search(PlanEmployeeAssignmentSearchRequest.builder() + .planEmployeeAssignmentSearchCriteria(planEmployeeAssignmentSearchCriteria) + .requestInfo(planRequest.getRequestInfo()).build()); + + if(CollectionUtils.isEmpty(planEmployeeAssignmentResponse.getPlanEmployeeAssignment())) + throw new CustomException(PLAN_EMPLOYEE_ASSIGNMENT_NOT_FOUND_CODE, PLAN_EMPLOYEE_ASSIGNMENT_NOT_FOUND_MESSAGE + planRequest.getPlan().getLocality()); + + validateJurisdiction(planRequest.getPlan(), + planEmployeeAssignmentResponse.getPlanEmployeeAssignment().get(0).getJurisdiction()); + } + + /** + * Validates that at least one jurisdiction exists within the hierarchy's boundary codes. + * If no jurisdiction is found in the boundary set, throws a custom exception. + * + * @param plan the plan containing the boundary ancestral path + * @param jurisdictions the list of jurisdictions to check against the boundary set + * @throws CustomException if none of the jurisdictions are present in the boundary codes + */ + public void validateJurisdiction(Plan plan, Set jurisdictions) { + Set boundarySet = new HashSet<>(Arrays.asList(plan.getBoundaryAncestralPath() + .split(PIPE_REGEX))); + + // Check if any jurisdiction is present in the boundary set + if (jurisdictions.stream().noneMatch(boundarySet::contains)) + throw new CustomException(JURISDICTION_NOT_FOUND_CODE, JURISDICTION_NOT_FOUND_MESSAGE); + + // Enrich jurisdiction of current assignee + plan.setAssigneeJurisdiction(new ArrayList<>(jurisdictions)); + + } + + /** + * Validates the boundary code provided in plan request against boundary service. + * + * @param boundarySearchResponse response from the boundary service. + * @param plan Plan record whose loclality is to be validated. + */ + private void validateBoundaryCode(BoundarySearchResponse boundarySearchResponse, Plan plan) { + HierarchyRelation tenantBoundary = boundarySearchResponse.getTenantBoundary().get(0); + + if (CollectionUtils.isEmpty(tenantBoundary.getBoundary())) { + throw new CustomException(NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_CODE, NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_MESSAGE); + } + + // Enrich the boundary ancestral path and jurisdiction mapping for the provided boundary code + if(plan.isRequestFromResourceEstimationConsumer()) + planEnricher.enrichBoundaryAncestralPath(plan, tenantBoundary); + } + + /** + * @param bulkPlanRequest + */ + public void validateBulkPlanUpdate(BulkPlanRequest bulkPlanRequest) { + CampaignResponse campaignResponse = campaignUtil.fetchCampaignData(bulkPlanRequest.getRequestInfo(), bulkPlanRequest.getPlans().get(0).getCampaignId(), bulkPlanRequest.getPlans().get(0).getTenantId()); + BoundaryTypeHierarchyResponse boundaryTypeHierarchyResponse = boundaryUtil.fetchBoundaryHierarchy(bulkPlanRequest.getRequestInfo(), bulkPlanRequest.getPlans().get(0).getTenantId(), campaignResponse.getCampaignDetails().get(0).getHierarchyType()); + + // Validate attributes across each plan in the bulk request + validatePlanAttributes(bulkPlanRequest); + + // Validate if plans provided in the request body exist + validatePlanExistence(bulkPlanRequest); + + // Validate plan employee assignment and jurisdiction + validatePlanEmployeeAssignmentAndJurisdiction(bulkPlanRequest); + + // Enrich jurisdiction mapping in plan + planEnricher.enrichJurisdictionMapping(bulkPlanRequest.getPlans(), boundaryTypeHierarchyResponse.getBoundaryHierarchy().get(0)); + } + + /** + * + * @param bulkPlanRequest + */ + private void validatePlanEmployeeAssignmentAndJurisdiction(BulkPlanRequest bulkPlanRequest) { + // Prepare plan employee assignment search criteria + PlanEmployeeAssignmentSearchCriteria planEmployeeAssignmentSearchCriteria = PlanEmployeeAssignmentSearchCriteria + .builder() + .tenantId(bulkPlanRequest.getPlans().get(0).getTenantId()) + .employeeId(Collections.singletonList(bulkPlanRequest.getRequestInfo().getUserInfo().getUuid())) + .planConfigurationId(bulkPlanRequest.getPlans().get(0).getPlanConfigurationId()) + .role(config.getPlanEstimationApproverRoles()) + .build(); + + // Fetch plan employee assignment + PlanEmployeeAssignmentResponse planEmployeeAssignmentResponse = planEmployeeService.search(PlanEmployeeAssignmentSearchRequest.builder() + .planEmployeeAssignmentSearchCriteria(planEmployeeAssignmentSearchCriteria) + .requestInfo(bulkPlanRequest.getRequestInfo()) + .build()); + + // Throw exception if the employee taking action is not a part of plan + if(CollectionUtils.isEmpty(planEmployeeAssignmentResponse.getPlanEmployeeAssignment())) { + throw new CustomException(PLAN_EMPLOYEE_ASSIGNMENT_NOT_FOUND_CODE, + PLAN_EMPLOYEE_ASSIGNMENT_NOT_FOUND_MESSAGE); + } + + // Validate jurisdiction for each plan + bulkPlanRequest.getPlans().forEach(plan -> validateJurisdiction(plan, + planEmployeeAssignmentResponse.getPlanEmployeeAssignment().get(0).getJurisdiction())); + + } + + /** + * + * @param bulkPlanRequest + */ + private void validatePlanAttributes(BulkPlanRequest bulkPlanRequest) { + if(bulkPlanRequest.getPlans().stream().map(Plan :: getId).collect(Collectors.toSet()).size() + != bulkPlanRequest.getPlans().size()) { + throw new CustomException("BULK_UPDATE_ERROR", + "Plans provided in the bulk update request are not unique."); + } + + if(!bulkPlanRequest.getPlans().stream().allMatch(plan -> + plan.getTenantId().equals(bulkPlanRequest.getPlans().get(0).getTenantId()) && + plan.getPlanConfigurationId().equals(bulkPlanRequest.getPlans().get(0).getPlanConfigurationId()))) { + throw new CustomException("BULK_UPDATE_ERROR", + "Tenant id and plan configuration ids should be same across all entries for bulk update."); + } + + bulkPlanRequest.getPlans().forEach(plan -> { + if(ObjectUtils.isEmpty(plan.getWorkflow())) { + throw new CustomException("BULK_UPDATE_ERROR", + "Workflow information is mandatory for each entry for bulk update"); + } + }); + + if(!bulkPlanRequest.getPlans().stream().allMatch(plan -> + plan.getStatus().equals(bulkPlanRequest.getPlans().get(0).getStatus()) && + plan.getWorkflow().getAction().equals(bulkPlanRequest.getPlans().get(0).getWorkflow().getAction()))) { + throw new CustomException("BULK_UPDATE_ERROR", + "All entries should be in the same state for bulk transitioning plan records."); + } + + } + + /** + * + * @param bulkPlanRequest + */ + private void validatePlanExistence(BulkPlanRequest bulkPlanRequest) { + // Get all plan ids to validate existence + List planListFromDatabase = planRepository.search(PlanSearchCriteria.builder() + .ids(bulkPlanRequest.getPlans().stream().map(Plan :: getId).collect(Collectors.toSet())) + .offset(0) + .limit(bulkPlanRequest.getPlans().size()) + .build()); + + // If plan id provided is invalid, throw an exception + if (planListFromDatabase.size() != bulkPlanRequest.getPlans().size()) { + throw new CustomException(INVALID_PLAN_ID_CODE, INVALID_PLAN_ID_MESSAGE); + } + + // Enrich ancestral materialized path for each plan object being passed in the request + enrichAncestralMaterializedPath(bulkPlanRequest, planListFromDatabase); + + } + + /** + * + * @param bulkPlanRequest + * @param planListFromDatabase + */ + private void enrichAncestralMaterializedPath(BulkPlanRequest bulkPlanRequest, List planListFromDatabase) { + Map planIdVsAncestralMaterializedPathMap = planListFromDatabase.stream() + .collect(Collectors.toMap(Plan :: getId, Plan :: getBoundaryAncestralPath)); + + bulkPlanRequest.getPlans().forEach(plan -> + plan.setBoundaryAncestralPath(planIdVsAncestralMaterializedPathMap + .get(plan.getId())) + ); + } +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/service/enrichment/EnrichmentService.java b/health-services/plan-service/src/main/java/digit/service/enrichment/EnrichmentService.java index 86c1fdb4b81..7dfb66f4a64 100644 --- a/health-services/plan-service/src/main/java/digit/service/enrichment/EnrichmentService.java +++ b/health-services/plan-service/src/main/java/digit/service/enrichment/EnrichmentService.java @@ -1,33 +1,37 @@ package digit.service.enrichment; import digit.config.Configuration; -import digit.web.models.File; -import digit.web.models.PlanConfiguration; -import digit.web.models.PlanConfigurationRequest; -import digit.web.models.ResourceMapping; +import digit.util.CommonUtil; +import digit.web.models.*; import lombok.extern.slf4j.Slf4j; import org.egov.common.utils.UUIDEnrichmentUtil; import org.egov.tracer.model.CustomException; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; import java.util.List; -import static org.egov.common.utils.AuditDetailsEnrichmentUtil.prepareAuditDetails; -import org.springframework.util.ObjectUtils; +import static digit.config.ServiceConstants.DRAFT_STATUS; +import static org.egov.common.utils.AuditDetailsEnrichmentUtil.prepareAuditDetails; @Component @Slf4j public class EnrichmentService { private Configuration config; - public EnrichmentService(Configuration config) { + private CommonUtil commonUtil; + + public EnrichmentService(Configuration config, CommonUtil commonUtil) { this.config = config; + this.commonUtil = commonUtil; } /** * Enriches the PlanConfigurationRequest for creating a new plan configuration. * Enriches the given plan configuration with generated IDs for plan, files, assumptions, operations, and resource mappings, * validates user information, and enriches audit details for create operation. + * * @param request The PlanConfigurationRequest to be enriched. * @throws CustomException if user information is missing in the request. */ @@ -35,24 +39,35 @@ public void enrichCreate(PlanConfigurationRequest request) { PlanConfiguration planConfiguration = request.getPlanConfiguration(); log.info("Enriching plan config with generated IDs"); + //set Draft status on create + planConfiguration.setStatus(DRAFT_STATUS); + // Generate id for plan configuration UUIDEnrichmentUtil.enrichRandomUuid(planConfiguration, "id"); // Generate id for files - planConfiguration.getFiles().forEach(file -> { - UUIDEnrichmentUtil.enrichRandomUuid(file, "id"); - enrichActiveForResourceMapping(file, planConfiguration.getResourceMapping()); - }); - + if (!CollectionUtils.isEmpty(planConfiguration.getFiles())) { + planConfiguration.getFiles().forEach(file -> { + UUIDEnrichmentUtil.enrichRandomUuid(file, "id"); + enrichActiveForResourceMapping(file, planConfiguration.getResourceMapping()); + }); + } // Generate id for assumptions - planConfiguration.getAssumptions().forEach(assumption -> UUIDEnrichmentUtil.enrichRandomUuid(assumption, "id")); + if (!CollectionUtils.isEmpty(planConfiguration.getAssumptions())) { + planConfiguration.getAssumptions().forEach(assumption -> UUIDEnrichmentUtil.enrichRandomUuid(assumption, "id")); + } + // Generate id for operations - planConfiguration.getOperations().forEach(operation -> UUIDEnrichmentUtil.enrichRandomUuid(operation, "id")); + if (!CollectionUtils.isEmpty(planConfiguration.getOperations())) { + planConfiguration.getOperations().forEach(operation -> UUIDEnrichmentUtil.enrichRandomUuid(operation, "id")); + } // Generate id for resource mappings - planConfiguration.getResourceMapping().forEach(resourceMapping -> UUIDEnrichmentUtil.enrichRandomUuid(resourceMapping, "id")); + if (!CollectionUtils.isEmpty(planConfiguration.getResourceMapping())) { + planConfiguration.getResourceMapping().forEach(resourceMapping -> UUIDEnrichmentUtil.enrichRandomUuid(resourceMapping, "id")); + } planConfiguration.setAuditDetails(prepareAuditDetails(planConfiguration.getAuditDetails(), request.getRequestInfo(), Boolean.TRUE)); } @@ -60,6 +75,7 @@ public void enrichCreate(PlanConfigurationRequest request) { /** * Enriches the PlanConfigurationRequest for updating an existing plan configuration. * This method enriches the plan configuration for update, validates user information, and enriches audit details for update operation. + * * @param request The PlanConfigurationRequest to be enriched. * @throws CustomException if user information is missing in the request. */ @@ -67,41 +83,54 @@ public void enrichUpdate(PlanConfigurationRequest request) { PlanConfiguration planConfiguration = request.getPlanConfiguration(); // Generate id for Files - planConfiguration.getFiles().forEach(file -> { - if (ObjectUtils.isEmpty(file.getId())) { - UUIDEnrichmentUtil.enrichRandomUuid(file, "id"); - } - enrichActiveForResourceMapping(file, request.getPlanConfiguration().getResourceMapping()); - }); + if (!CollectionUtils.isEmpty(planConfiguration.getFiles())) { + planConfiguration.getFiles().forEach(file -> { + if (ObjectUtils.isEmpty(file.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(file, "id"); + } + enrichActiveForResourceMapping(file, request.getPlanConfiguration().getResourceMapping()); + }); + } // Generate id for Assumptions - planConfiguration.getAssumptions().forEach(assumption -> { - if (ObjectUtils.isEmpty(assumption.getId())) { - UUIDEnrichmentUtil.enrichRandomUuid(assumption, "id"); - } - }); + if (!CollectionUtils.isEmpty(planConfiguration.getAssumptions())) { + planConfiguration.getAssumptions().forEach(assumption -> { + if (ObjectUtils.isEmpty(assumption.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(assumption, "id"); + } + }); + } // Generate id for Operations - planConfiguration.getOperations().forEach(operation -> { - if (ObjectUtils.isEmpty(operation.getId())) { - UUIDEnrichmentUtil.enrichRandomUuid(operation, "id"); - } - }); + if (!CollectionUtils.isEmpty(planConfiguration.getOperations())) { + planConfiguration.getOperations().forEach(operation -> { + if (ObjectUtils.isEmpty(operation.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(operation, "id"); + } + }); + } // Generate id for ResourceMappings - planConfiguration.getResourceMapping().forEach(resourceMapping -> { - if (ObjectUtils.isEmpty(resourceMapping.getId())) { - UUIDEnrichmentUtil.enrichRandomUuid(resourceMapping, "id"); - } - }); + if (!CollectionUtils.isEmpty(planConfiguration.getResourceMapping())) { + planConfiguration.getResourceMapping().forEach(resourceMapping -> { + if (ObjectUtils.isEmpty(resourceMapping.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(resourceMapping, "id"); + } + }); + } planConfiguration.setAuditDetails(prepareAuditDetails(request.getPlanConfiguration().getAuditDetails(), request.getRequestInfo(), Boolean.FALSE)); + + //enrich execution order for operations on setup complete + if (commonUtil.checkForEmptyOperationsOrAssumptions(planConfiguration)) { + enrichExecutionOrderForOperations(planConfiguration); + } } /** * Sets all corresponding resource mappings to inactive if the given file is inactive. * - * @param file the file object which may be inactive + * @param file the file object which may be inactive * @param resourceMappings the list of resource mappings to update */ public void enrichActiveForResourceMapping(File file, List resourceMappings) { @@ -120,34 +149,55 @@ public void enrichActiveForResourceMapping(File file, List reso * * @param request the plan configuration request containing the plan configuration to be enriched */ - public void enrichPlanConfigurationBeforeValidation(PlanConfigurationRequest request) - { + public void enrichPlanConfigurationBeforeValidation(PlanConfigurationRequest request) { PlanConfiguration planConfiguration = request.getPlanConfiguration(); // For Files, Operations, Assumptions and Resource Mappings override active to be True - planConfiguration.getFiles().forEach(file -> { - if (ObjectUtils.isEmpty(file.getId())) { - file.setActive(Boolean.TRUE); - } - }); - - planConfiguration.getOperations().forEach(operation -> { - if (ObjectUtils.isEmpty(operation.getId())) { - operation.setActive(Boolean.TRUE); - } - }); - - planConfiguration.getAssumptions().forEach(assumption -> { - if (ObjectUtils.isEmpty(assumption.getId())) { - assumption.setActive(Boolean.TRUE); - } - }); - - planConfiguration.getResourceMapping().forEach(resourceMapping -> { - if (ObjectUtils.isEmpty(resourceMapping.getId())) { - resourceMapping.setActive(Boolean.TRUE); - } - }); + if (!CollectionUtils.isEmpty(planConfiguration.getFiles())) { + planConfiguration.getFiles().forEach(file -> { + if (ObjectUtils.isEmpty(file.getId())) { + file.setActive(Boolean.TRUE); + } + }); + } + + if (!CollectionUtils.isEmpty(planConfiguration.getOperations())) { + planConfiguration.getOperations().forEach(operation -> { + if (ObjectUtils.isEmpty(operation.getId())) { + operation.setActive(Boolean.TRUE); + } + }); + } + + if (!CollectionUtils.isEmpty(planConfiguration.getAssumptions())) { + planConfiguration.getAssumptions().forEach(assumption -> { + if (ObjectUtils.isEmpty(assumption.getId())) { + assumption.setActive(Boolean.TRUE); + } + }); + } + + if (!CollectionUtils.isEmpty(planConfiguration.getResourceMapping())) { + planConfiguration.getResourceMapping().forEach(resourceMapping -> { + if (ObjectUtils.isEmpty(resourceMapping.getId())) { + resourceMapping.setActive(Boolean.TRUE); + } + }); + } + } + + /** + * Sets a sequential execution order for each operation in the given PlanConfiguration. + * + * @param planConfiguration the configuration containing operations to order + */ + public void enrichExecutionOrderForOperations(PlanConfiguration planConfiguration) { + int executionOrderCounter = 1; + + for (Operation operation : planConfiguration.getOperations()) { + if(operation.getActive()) + operation.setExecutionOrder(executionOrderCounter++); + } } } diff --git a/health-services/plan-service/src/main/java/digit/service/enrichment/PlanEmployeeAssignmentEnricher.java b/health-services/plan-service/src/main/java/digit/service/enrichment/PlanEmployeeAssignmentEnricher.java new file mode 100644 index 00000000000..c4072ca637e --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/enrichment/PlanEmployeeAssignmentEnricher.java @@ -0,0 +1,71 @@ +package digit.service.enrichment; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import digit.repository.PlanEmployeeAssignmentRepository; +import digit.util.CommonUtil; +import digit.web.models.*; +import org.egov.common.utils.UUIDEnrichmentUtil; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static digit.config.ServiceConstants.*; +import static org.egov.common.utils.AuditDetailsEnrichmentUtil.prepareAuditDetails; + +@Component +public class PlanEmployeeAssignmentEnricher { + + private ObjectMapper objectMapper; + + private PlanEmployeeAssignmentRepository repository; + + private CommonUtil commonUtil; + + public PlanEmployeeAssignmentEnricher(ObjectMapper objectMapper, CommonUtil commonUtil, PlanEmployeeAssignmentRepository repository) { + this.objectMapper = objectMapper; + this.commonUtil = commonUtil; + this.repository = repository; + } + + /** + * Enriches the PlanEmployeeAssignmentRequest with id and audit details and sets active as true. + * + * @param request The PlanEmployeeAssignmentRequest body to be enriched + */ + public void enrichCreate(PlanEmployeeAssignmentRequest request) { + PlanEmployeeAssignment planEmployeeAssignment = request.getPlanEmployeeAssignment(); + + // Generate id for Plan employee assignment body + UUIDEnrichmentUtil.enrichRandomUuid(planEmployeeAssignment, "id"); + + // Set active true + planEmployeeAssignment.setActive(Boolean.TRUE); + + // Set Audit Details for Plan employee assignment + planEmployeeAssignment.setAuditDetails(prepareAuditDetails(planEmployeeAssignment.getAuditDetails(), + request.getRequestInfo(), + Boolean.TRUE)); + + // Add plan config name to which the employee is mapped + planEmployeeAssignment.setPlanConfigurationName(commonUtil.getPlanConfigName(planEmployeeAssignment.getTenantId(), planEmployeeAssignment.getPlanConfigurationId())); + } + + /** + * Enriches the PlanEmployeeAssignmentRequest for updating an existing plan employee assignment with audit details. + * + * @param request The PlanEmployeeAssignmentRequest body to be enriched + */ + public void enrichUpdate(PlanEmployeeAssignmentRequest request) { + PlanEmployeeAssignment planEmployeeAssignment = request.getPlanEmployeeAssignment(); + + // Set Audit Details for Plan employee assignment update + planEmployeeAssignment.setAuditDetails(prepareAuditDetails(planEmployeeAssignment.getAuditDetails(), + request.getRequestInfo(), + Boolean.FALSE)); + } +} diff --git a/health-services/plan-service/src/main/java/digit/service/enrichment/PlanFacilityEnricher.java b/health-services/plan-service/src/main/java/digit/service/enrichment/PlanFacilityEnricher.java new file mode 100644 index 00000000000..a07530dbfd2 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/enrichment/PlanFacilityEnricher.java @@ -0,0 +1,213 @@ +package digit.service.enrichment; + +import digit.util.BoundaryUtil; +import digit.util.CensusUtil; +import digit.util.CommonUtil; +import digit.web.models.PlanFacility; +import digit.web.models.PlanFacilityRequest; +import digit.web.models.PlanFacilitySearchCriteria; +import digit.web.models.PlanFacilitySearchRequest; +import digit.web.models.boundary.BoundarySearchResponse; +import digit.web.models.boundary.EnrichedBoundary; +import digit.web.models.census.*; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.utils.AuditDetailsEnrichmentUtil; +import org.egov.common.utils.UUIDEnrichmentUtil; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +import static digit.config.ServiceConstants.*; +import static org.egov.common.utils.AuditDetailsEnrichmentUtil.prepareAuditDetails; + +@Component +@Slf4j +public class PlanFacilityEnricher { + + private CommonUtil commonUtil; + + private CensusUtil censusUtil; + + private BoundaryUtil boundaryUtil; + + public PlanFacilityEnricher(CommonUtil commonUtil, CensusUtil censusUtil, BoundaryUtil boundaryUtil) { + this.commonUtil = commonUtil; + this.censusUtil = censusUtil; + this.boundaryUtil = boundaryUtil; + } + + /** + * Enriches the plan facility create request + * + * @param planFacilityRequest + */ + public void enrichPlanFacilityCreate(@Valid PlanFacilityRequest planFacilityRequest) { + // Generate id for plan facility + UUIDEnrichmentUtil.enrichRandomUuid(planFacilityRequest.getPlanFacility(), "id"); + + // Enrich audit details + planFacilityRequest.getPlanFacility().setAuditDetails(AuditDetailsEnrichmentUtil + .prepareAuditDetails(planFacilityRequest.getPlanFacility().getAuditDetails(), + planFacilityRequest.getRequestInfo(), Boolean.TRUE)); + + //Set Active + planFacilityRequest.getPlanFacility().setActive(Boolean.TRUE); + + // Add plan config name to which the facility is mapped + planFacilityRequest.getPlanFacility().setPlanConfigurationName(commonUtil.getPlanConfigName(planFacilityRequest.getPlanFacility().getTenantId(), planFacilityRequest.getPlanFacility().getPlanConfigurationId())); + } + + public void enrichJurisdictionMapping(PlanFacilityRequest request, String hierarchyType) { + BoundarySearchResponse boundarySearchResponse = boundaryUtil.fetchBoundaryData(request.getRequestInfo(), request.getPlanFacility().getResidingBoundary(), request.getPlanFacility().getTenantId(), hierarchyType, Boolean.TRUE, Boolean.FALSE); + + EnrichedBoundary boundary = boundarySearchResponse.getTenantBoundary().get(0).getBoundary().get(0); + Map jurisdictionMapping = new LinkedHashMap<>(); + + jurisdictionMapping.put(boundary.getBoundaryType(), boundary.getCode()); + StringBuilder boundaryAncestralPath = new StringBuilder(boundary.getCode()); + + // Iterate through the child boundary until there are no more + while (!CollectionUtils.isEmpty(boundary.getChildren())) { + boundary = boundary.getChildren().get(0); + + boundaryAncestralPath.append("|").append(boundary.getCode()); + jurisdictionMapping.put(boundary.getBoundaryType(), boundary.getCode()); + } + + // Setting the boundary ancestral path for the provided boundary + request.getPlanFacility().setBoundaryAncestralPath(boundaryAncestralPath.toString()); + + // Setting jurisdiction mapping for the provided boundary + request.getPlanFacility().setJurisdictionMapping(jurisdictionMapping); + } + + /** + * Enriches the plan facility update request + * + * @param planFacilityRequest The PlanFacilityRequest object contains the plan facility to be enriched. + */ + public void enrichPlanFacilityUpdate(PlanFacilityRequest planFacilityRequest) { + PlanFacility planFacility = planFacilityRequest.getPlanFacility(); + + //enrich audit details + planFacility.setAuditDetails(prepareAuditDetails(planFacilityRequest.getPlanFacility().getAuditDetails(), planFacilityRequest.getRequestInfo(), Boolean.FALSE)); + + // enrich serving population + enrichServingPopulation(planFacilityRequest); + } + + /** + * Enriches serving population based on the serving boundaries provided. + * + * @param planFacilityRequest plan facility request whose serving population is to be enriched. + */ + private void enrichServingPopulation(PlanFacilityRequest planFacilityRequest) { + PlanFacility planFacility = planFacilityRequest.getPlanFacility(); + + // Prepare list of boundaries whose census records are to be fetched + Set boundariesToBeSearched = new HashSet<>(planFacility.getServiceBoundaries()); + boundariesToBeSearched.addAll(planFacility.getInitiallySetServiceBoundaries()); + + if(!CollectionUtils.isEmpty(boundariesToBeSearched)) { + CensusSearchCriteria censusSearchCriteria = CensusSearchCriteria.builder() + .tenantId(planFacility.getTenantId()) + .source(planFacility.getPlanConfigurationId()) + .areaCodes(new ArrayList<>(boundariesToBeSearched)) + .limit(boundariesToBeSearched.size()) + .build(); + + CensusResponse censusResponse = censusUtil.fetchCensusRecords(CensusSearchRequest.builder() + .requestInfo(planFacilityRequest.getRequestInfo()) + .censusSearchCriteria(censusSearchCriteria) + .build()); + + // Creates a population map based on the confirmed target population of the boundary + Map boundaryToPopMap = getPopulationMap(censusResponse.getCensus()); + + // Get existing servingPopulation or default to 0 + BigDecimal servingPopulation = (BigDecimal) commonUtil.extractFieldsFromJsonObject(planFacility.getAdditionalDetails(), SERVING_POPULATION_CODE); + + updateServingPopulation(boundariesToBeSearched, planFacility, boundaryToPopMap, servingPopulation); + } + } + + /** + * Creates a mapping of boundary with it's confirmed target population. + * + * @param censusList Census records for the given list of serving boundaries. + * @return returns a map of boundary with its confirmed target population. + */ + private Map getPopulationMap(List censusList) { + Map boundaryToPopMap = new HashMap<>(); + + for (Census census : censusList) { + Map additionalFieldsMap = census.getAdditionalFields().stream() + .collect(Collectors.toMap(AdditionalField::getKey, AdditionalField::getValue)); + + Long confirmedTargetPopulation = 0L; + + // Get confirmed target population based on campaign type. + if (additionalFieldsMap.containsKey(CONFIRMED_TARGET_POPULATION_AGE_3TO11)) { + confirmedTargetPopulation = additionalFieldsMap.get(CONFIRMED_TARGET_POPULATION_AGE_3TO11) + .add(additionalFieldsMap.get(CONFIRMED_TARGET_POPULATION_AGE_12TO59)) + .longValue(); + } else if(additionalFieldsMap.containsKey(CONFIRMED_TARGET_POPULATION)){ + confirmedTargetPopulation = additionalFieldsMap.get(CONFIRMED_TARGET_POPULATION).longValue(); + } + + // Map the boundary code with it's confirmed target population. + boundaryToPopMap.put(census.getBoundaryCode(), confirmedTargetPopulation); + } + + return boundaryToPopMap; + } + + private void updateServingPopulation(Set boundariesToBeSearched, PlanFacility planFacility, Map boundaryToPopMap, BigDecimal servingPopulation) { + Set currentServiceBoundaries = new HashSet<>(planFacility.getServiceBoundaries()); + Set initialServiceBoundaries = new HashSet<>(planFacility.getInitiallySetServiceBoundaries()); + + for(String boundary : boundariesToBeSearched) { + Long totalPopulation = boundaryToPopMap.get(boundary); + + if (!currentServiceBoundaries.contains(boundary)) { + servingPopulation = servingPopulation.subtract(BigDecimal.valueOf(totalPopulation)); + } else if (!initialServiceBoundaries.contains(boundary)) { + servingPopulation = servingPopulation.add(BigDecimal.valueOf(totalPopulation)); + } + } + Map fieldToUpdate = new HashMap<>(); + fieldToUpdate.put(SERVING_POPULATION_CODE, servingPopulation); + + planFacility.setAdditionalDetails(commonUtil.updateFieldInAdditionalDetails(planFacility.getAdditionalDetails(), fieldToUpdate)); + } + + /** + * Enriches plan facility search request + * + * @param planFacilitySearchRequest + */ + public void enrichSearchRequest(PlanFacilitySearchRequest planFacilitySearchRequest) { + PlanFacilitySearchCriteria planFacilitySearchCriteria = planFacilitySearchRequest.getPlanFacilitySearchCriteria(); + + // Filter map for filtering facility meta data present in additional details + Map filtersMap = new LinkedHashMap<>(); + + // Add facility status as a filter if present in search criteria + if(!ObjectUtils.isEmpty(planFacilitySearchCriteria.getFacilityStatus())) { + filtersMap.put(FACILITY_STATUS_SEARCH_PARAMETER_KEY, planFacilitySearchCriteria.getFacilityStatus()); + } + + // Add facility type as a filter if present in search criteria + if(!ObjectUtils.isEmpty(planFacilitySearchCriteria.getFacilityType())) { + filtersMap.put(FACILITY_TYPE_SEARCH_PARAMETER_KEY, planFacilitySearchCriteria.getFacilityType()); + } + + if(!CollectionUtils.isEmpty(filtersMap)) + planFacilitySearchCriteria.setFiltersMap(filtersMap); + } +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/service/validator/PlanConfigurationValidator.java b/health-services/plan-service/src/main/java/digit/service/validator/PlanConfigurationValidator.java index 22d316b707e..58041c3324d 100644 --- a/health-services/plan-service/src/main/java/digit/service/validator/PlanConfigurationValidator.java +++ b/health-services/plan-service/src/main/java/digit/service/validator/PlanConfigurationValidator.java @@ -1,25 +1,24 @@ package digit.service.validator; +import com.fasterxml.jackson.databind.JsonNode; import com.jayway.jsonpath.JsonPath; -import digit.config.ServiceConstants; import digit.repository.PlanConfigurationRepository; +import digit.util.CampaignUtil; +import digit.util.CommonUtil; import digit.util.MdmsUtil; -import digit.util.ServiceUtil; +import digit.util.MdmsV2Util; import digit.web.models.*; - -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; - +import digit.web.models.mdmsV2.Mdms; +import digit.web.models.projectFactory.CampaignResponse; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.egov.common.utils.MultiStateInstanceUtil; import org.egov.tracer.model.CustomException; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import org.springframework.util.ObjectUtils; + +import java.util.*; +import java.util.stream.Collectors; import static digit.config.ServiceConstants.*; @@ -27,60 +26,96 @@ @Slf4j public class PlanConfigurationValidator { - private MdmsUtil mdmsUtil; + private MdmsV2Util mdmsV2Util; + private PlanConfigurationRepository planConfigRepository; + private CommonUtil commonUtil; - private ServiceUtil serviceUtil; private MultiStateInstanceUtil centralInstanceUtil; - public PlanConfigurationValidator(MdmsUtil mdmsUtil, PlanConfigurationRepository planConfigRepository, ServiceUtil serviceUtil, MultiStateInstanceUtil centralInstanceUtil) { + private CampaignUtil campaignUtil; + + public PlanConfigurationValidator(MdmsUtil mdmsUtil, MdmsV2Util mdmsV2Util, PlanConfigurationRepository planConfigRepository, CommonUtil commonUtil, MultiStateInstanceUtil centralInstanceUtil, CampaignUtil campaignUtil) { this.mdmsUtil = mdmsUtil; + this.mdmsV2Util = mdmsV2Util; this.planConfigRepository = planConfigRepository; - this.serviceUtil = serviceUtil; - this.centralInstanceUtil = centralInstanceUtil; + this.commonUtil = commonUtil; + this.centralInstanceUtil = centralInstanceUtil; + this.campaignUtil = campaignUtil; } /** * Validates the create request for plan configuration, including assumptions against MDMS data. + * * @param request The create request for plan configuration. */ public void validateCreate(PlanConfigurationRequest request) { PlanConfiguration planConfiguration = request.getPlanConfiguration(); String rootTenantId = centralInstanceUtil.getStateLevelTenant(planConfiguration.getTenantId()); Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), rootTenantId); + List mdmsV2Data = mdmsV2Util.fetchMdmsV2Data(request.getRequestInfo(), rootTenantId, MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_SCHEMA_VEHICLE_DETAILS, null); + CampaignResponse campaignResponse = campaignUtil.fetchCampaignData(request.getRequestInfo(), request.getPlanConfiguration().getCampaignId(), rootTenantId); + + // Validate if the plan configuration for the provided name and campaign id already exists + validateDuplicateRecord(planConfiguration); + + // Validate if campaign id exists against project factory + validateCampaignId(campaignResponse); // Validate that the assumption keys in the request are present in the MDMS data validateAssumptionKeyAgainstMDMS(request, mdmsData); - // Validate that the assumption values in the plan configuration are correct - validateAssumptionValue(planConfiguration); - - // Validate the filestore ID in the plan configuration's request mappings - validateFilestoreId(planConfiguration); + // Validate that the assumption keys in the request are unique + validateAssumptionUniqueness(planConfiguration); // Validate that the template identifiers in the request match those in the MDMS data validateTemplateIdentifierAgainstMDMS(request, mdmsData); - // Validate that the inputs for operations in the request match those in the MDMS data - validateOperationsInputAgainstMDMS(request, mdmsData); - - // Validate that the resource mappings in the request match those in the MDMS data - validateResourceMappingAgainstMDMS(request, mdmsData); - - // Validate the uniqueness of the 'mappedTo' fields in the resource mappings - validateMappedToUniqueness(planConfiguration.getResourceMapping()); + //Validating operation's input and assumptionValue fields + validateOperations(request, campaignResponse); //Validating plan config name against MDMS data validatePlanConfigName(request, mdmsData); // Validate the user information in the request - validateUserInfo(request); + commonUtil.validateUserInfo(request.getRequestInfo()); + + // Validates the vehicle id from additional details object against the data from mdms v2 + validateVehicleIdsFromAdditionalDetailsAgainstMDMS(request, mdmsV2Data); } + /** + * Validates if plan configuration for the provided name and campaign id already exists + * + * @param planConfiguration the plan configuration from the create request + */ + private void validateDuplicateRecord(PlanConfiguration planConfiguration) { + List planConfigurationsFromSearch = planConfigRepository.search(PlanConfigurationSearchCriteria.builder() + .tenantId(planConfiguration.getTenantId()) + .campaignId(planConfiguration.getCampaignId()) + .name(planConfiguration.getName()) + .build()); + + if (!CollectionUtils.isEmpty(planConfigurationsFromSearch)) { + throw new CustomException(PLAN_CONFIGURATION_ALREADY_EXISTS_CODE, PLAN_CONFIGURATION_ALREADY_EXISTS_MESSAGE); + } + } + + /** + * Validates campaign ID from request against project factory + * + * @param campaignResponse The campaign details response from project factory + */ + private void validateCampaignId(CampaignResponse campaignResponse) { + if (CollectionUtils.isEmpty(campaignResponse.getCampaignDetails())) { + throw new CustomException(NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_CODE, NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_MESSAGE); + } + } + /** * Validates the name of the plan configuration against a regex pattern retrieved from MDMS data. * @@ -89,12 +124,10 @@ public void validateCreate(PlanConfigurationRequest request) { * @throws CustomException if the JSONPath evaluation fails, the name validation list from MDMS is empty, * or the plan configuration name validation fails. */ - public void validatePlanConfigName(PlanConfigurationRequest request, Object mdmsData) - { + public void validatePlanConfigName(PlanConfigurationRequest request, Object mdmsData) { PlanConfiguration planConfiguration = request.getPlanConfiguration(); final String jsonPathForNameValidation = JSON_ROOT_PATH + MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_MASTER_NAME_VALIDATION + "[*].data"; - List nameValidationListFromMDMS = null; try { nameValidationListFromMDMS = JsonPath.read(mdmsData, jsonPathForNameValidation); @@ -108,10 +141,9 @@ public void validatePlanConfigName(PlanConfigurationRequest request, Object mdms } String regexPattern = (String) nameValidationListFromMDMS.get(0); - if (!serviceUtil.validateStringAgainstRegex(regexPattern, planConfiguration.getName())) { + if (!commonUtil.validateStringAgainstRegex(regexPattern, planConfiguration.getName())) { throw new CustomException(NAME_VALIDATION_FAILED_CODE, NAME_VALIDATION_FAILED_MESSAGE); } - } @@ -121,226 +153,129 @@ public void validatePlanConfigName(PlanConfigurationRequest request, Object mdms * * @param planConfiguration The plan configuration to validate. */ - public void validateAssumptionValue(PlanConfiguration planConfiguration) { - // Collect all active assumption keys - Set activeAssumptionKeys = planConfiguration.getAssumptions().stream() - .filter(Assumption::getActive) - .map(Assumption::getKey) - .collect(Collectors.toSet()); - - planConfiguration.getOperations().stream() - .filter(Operation::getActive) - .forEach(operation -> { - if (!activeAssumptionKeys.contains(operation.getAssumptionValue())) { - log.error("Assumption Value " + operation.getAssumptionValue() + " is not present in the list of active Assumption Keys"); - throw new CustomException(ASSUMPTION_VALUE_NOT_FOUND_CODE, ASSUMPTION_VALUE_NOT_FOUND_MESSAGE + " - " + operation.getAssumptionValue()); - } - }); - - } /** * Validates the assumption keys against MDMS data. - * @param request The request containing the plan configuration and the MDMS data. + * + * @param request The request containing the plan configuration and the MDMS data. * @param mdmsData The MDMS data. */ public void validateAssumptionKeyAgainstMDMS(PlanConfigurationRequest request, Object mdmsData) { PlanConfiguration planConfiguration = request.getPlanConfiguration(); - final String jsonPathForAssumption = JSON_ROOT_PATH + MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_MASTER_ASSUMPTION + "[*].assumptions[*]"; + if (!CollectionUtils.isEmpty(planConfiguration.getAssumptions())) { - List assumptionListFromMDMS = null; - try { - log.info(jsonPathForAssumption); - assumptionListFromMDMS = JsonPath.read(mdmsData, jsonPathForAssumption); - } catch (Exception e) { - log.error(e.getMessage()); - throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); - } + Object additionalDetails = request.getPlanConfiguration().getAdditionalDetails(); + if (additionalDetails == null) { + throw new CustomException(ADDITIONAL_DETAILS_MISSING_CODE, ADDITIONAL_DETAILS_MISSING_MESSAGE); + } - HashSet assumptionSetFromMDMS = new HashSet<>(assumptionListFromMDMS); - planConfiguration.getAssumptions().forEach(assumption -> { - if (!assumptionSetFromMDMS.contains(assumption.getKey())) { + String jsonPathForAssumption = commonUtil.createJsonPathForAssumption((String) commonUtil.extractFieldsFromJsonObject(additionalDetails, JSON_FIELD_CAMPAIGN_TYPE), + (String) commonUtil.extractFieldsFromJsonObject(additionalDetails, JSON_FIELD_DISTRIBUTION_PROCESS), + (String) commonUtil.extractFieldsFromJsonObject(additionalDetails, JSON_FIELD_REGISTRATION_PROCESS), + (String) commonUtil.extractFieldsFromJsonObject(additionalDetails, JSON_FIELD_RESOURCE_DISTRIBUTION_STRATEGY_CODE), + (String) commonUtil.extractFieldsFromJsonObject(additionalDetails, JSON_FIELD_IS_REGISTRATION_AND_DISTRIBUTION_TOGETHER)); + List assumptionListFromMDMS = null; + try { + log.info(jsonPathForAssumption); + assumptionListFromMDMS = JsonPath.read(mdmsData, jsonPathForAssumption); + } catch (Exception e) { + log.error(e.getMessage()); + throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); + } + + Set assumptionSetFromMDMS = new HashSet<>(assumptionListFromMDMS); + planConfiguration.getAssumptions().forEach(assumption -> { + if (assumption.getActive() && assumption.getSource() == Source.MDMS && !assumptionSetFromMDMS.contains(assumption.getKey())) { log.error(ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_MESSAGE + assumption.getKey()); - throw new CustomException(ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_CODE, ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_MESSAGE + " at JSONPath: " + jsonPathForAssumption); + throw new CustomException(ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_CODE, ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_MESSAGE + assumption.getKey() + " at JSONPath: " + jsonPathForAssumption); } - } - ); - + }); + } } /** - * Validates the file store IDs in the provided PlanConfiguration's Resource Mapping list. - * @param planConfiguration The PlanConfiguration to validate. + * Validates the uniqueness of assumption keys in the provided PlanConfiguration. + * If any duplicate keys are found, a CustomException is thrown. + * + * @param planConfig the PlanConfiguration object containing a list of Assumptions to validate + * @throws CustomException if a duplicate assumption key is found */ - public void validateFilestoreId(PlanConfiguration planConfiguration) { - Set fileStoreIds = planConfiguration.getFiles().stream() - .map(File::getFilestoreId) - .collect(Collectors.toSet()); + public void validateAssumptionUniqueness(PlanConfiguration planConfig) { + Set assumptionKeys = new HashSet<>(); - planConfiguration.getResourceMapping().stream().forEach(mapping -> { - if (!fileStoreIds.contains(mapping.getFilestoreId())) { - log.error("Resource Mapping " + mapping.getMappedTo() + " does not have valid fileStoreId " + mapping.getFilestoreId()); - throw new CustomException(FILESTORE_ID_INVALID_CODE, FILESTORE_ID_INVALID_MESSAGE); + for (Assumption assumption : planConfig.getAssumptions()) { + if (assumption.getActive() != Boolean.FALSE) { + if (assumptionKeys.contains(assumption.getKey())) { + throw new CustomException(DUPLICATE_ASSUMPTION_KEY_CODE, DUPLICATE_ASSUMPTION_KEY_MESSAGE + assumption.getKey()); + } + assumptionKeys.add(assumption.getKey()); } - }); - + } } /** * Validates the template identifiers of files in the PlanConfigurationRequest against the list of template identifiers * obtained from MDMS (Master Data Management System) data. * - * @param request The PlanConfigurationRequest containing the PlanConfiguration to validate. - * @param mdmsData The MDMS data containing template identifiers to validate against. + * @param request The PlanConfigurationRequest containing the PlanConfiguration to validate. + * @param mdmsData The MDMS data containing template identifiers to validate against. */ public void validateTemplateIdentifierAgainstMDMS(PlanConfigurationRequest request, Object mdmsData) { PlanConfiguration planConfiguration = request.getPlanConfiguration(); - final String jsonPathForTemplateIdentifier = JSON_ROOT_PATH + MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_MASTER_UPLOAD_CONFIGURATION + ".*.id"; - final String jsonPathForTemplateIdentifierIsRequired = JSON_ROOT_PATH + MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_MASTER_UPLOAD_CONFIGURATION + "[?(@.required == true)].id"; - - List templateIdentifierListFromMDMS = null; - List requiredTemplateIdentifierFromMDMS = null; - Set activeRequiredTemplates = new HashSet<>(); - - try { - log.info(jsonPathForTemplateIdentifier); - templateIdentifierListFromMDMS = JsonPath.read(mdmsData, jsonPathForTemplateIdentifier); - requiredTemplateIdentifierFromMDMS = JsonPath.read(mdmsData, jsonPathForTemplateIdentifierIsRequired); - } catch (Exception e) { - log.error(e.getMessage()); - throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); - } + if (!CollectionUtils.isEmpty(planConfiguration.getFiles())) { + final String jsonPathForTemplateIdentifier = JSON_ROOT_PATH + MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_MASTER_UPLOAD_CONFIGURATION + ".*.id"; + final String jsonPathForTemplateIdentifierIsRequired = JSON_ROOT_PATH + MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_MASTER_UPLOAD_CONFIGURATION + "[?(@.required == true)].id"; + + List templateIdentifierListFromMDMS = null; + List requiredTemplateIdentifierFromMDMS = null; + Set activeRequiredTemplates = new HashSet<>(); + + try { + log.info(jsonPathForTemplateIdentifier); + templateIdentifierListFromMDMS = JsonPath.read(mdmsData, jsonPathForTemplateIdentifier); + requiredTemplateIdentifierFromMDMS = JsonPath.read(mdmsData, jsonPathForTemplateIdentifierIsRequired); + } catch (Exception e) { + log.error(e.getMessage()); + throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); + } - HashSet templateIdentifierSetFromMDMS = new HashSet<>(templateIdentifierListFromMDMS); - HashSet requiredTemplateIdentifierSetFromMDMS = new HashSet<>(requiredTemplateIdentifierFromMDMS); + HashSet templateIdentifierSetFromMDMS = new HashSet<>(templateIdentifierListFromMDMS); + HashSet requiredTemplateIdentifierSetFromMDMS = new HashSet<>(requiredTemplateIdentifierFromMDMS); - for(File file : planConfiguration.getFiles()) - { - if(!templateIdentifierSetFromMDMS.contains(file.getTemplateIdentifier())) - { - log.error(TEMPLATE_IDENTIFIER_NOT_FOUND_IN_MDMS_MESSAGE + file.getTemplateIdentifier()); - throw new CustomException(TEMPLATE_IDENTIFIER_NOT_FOUND_IN_MDMS_CODE, TEMPLATE_IDENTIFIER_NOT_FOUND_IN_MDMS_MESSAGE); - } + for (File file : planConfiguration.getFiles()) { + if (!templateIdentifierSetFromMDMS.contains(file.getTemplateIdentifier())) { + log.error(TEMPLATE_IDENTIFIER_NOT_FOUND_IN_MDMS_MESSAGE + file.getTemplateIdentifier()); + throw new CustomException(TEMPLATE_IDENTIFIER_NOT_FOUND_IN_MDMS_CODE, TEMPLATE_IDENTIFIER_NOT_FOUND_IN_MDMS_MESSAGE); + } - if (file.getActive()) { // Check if the file is active - String templateIdentifier = file.getTemplateIdentifier(); - if (requiredTemplateIdentifierSetFromMDMS.contains(templateIdentifier)) { // Check if the template identifier is required - if (!activeRequiredTemplates.add(templateIdentifier)) { // Ensure only one active file per required template identifier - log.error(ONLY_ONE_FILE_OF_REQUIRED_TEMPLATE_IDENTIFIER_MESSAGE + file.getTemplateIdentifier()); - throw new CustomException(ONLY_ONE_FILE_OF_REQUIRED_TEMPLATE_IDENTIFIER_CODE, ONLY_ONE_FILE_OF_REQUIRED_TEMPLATE_IDENTIFIER_MESSAGE); + if (file.getActive()) { // Check if the file is active + String templateIdentifier = file.getTemplateIdentifier(); + if (requiredTemplateIdentifierSetFromMDMS.contains(templateIdentifier)) { // Check if the template identifier is required + if (!activeRequiredTemplates.add(templateIdentifier)) { // Ensure only one active file per required template identifier + log.error(ONLY_ONE_FILE_OF_REQUIRED_TEMPLATE_IDENTIFIER_MESSAGE + file.getTemplateIdentifier()); + throw new CustomException(ONLY_ONE_FILE_OF_REQUIRED_TEMPLATE_IDENTIFIER_CODE, ONLY_ONE_FILE_OF_REQUIRED_TEMPLATE_IDENTIFIER_MESSAGE); + } } } } - } - // Ensure at least one active file for each required template identifier - requiredTemplateIdentifierSetFromMDMS - .stream() - .forEach(requiredTemplate -> { + // Ensure at least one active file for each required template identifier + if(commonUtil.isSetupCompleted(planConfiguration)){ + requiredTemplateIdentifierSetFromMDMS.forEach(requiredTemplate -> { if (!activeRequiredTemplates.contains(requiredTemplate)) { log.error("Required Template Identifier " + requiredTemplate + " does not have any active file."); throw new CustomException(REQUIRED_TEMPLATE_IDENTIFIER_NOT_FOUND_CODE, REQUIRED_TEMPLATE_IDENTIFIER_NOT_FOUND_MESSAGE); } }); - - } - - - /** - * Validates the operations input against the Master Data Management System (MDMS) data. - * - * @param request The PlanConfigurationRequest containing the plan configuration and other details. - * @param mdmsData The MDMS data containing the master rule configure inputs. - */ - public void validateOperationsInputAgainstMDMS(PlanConfigurationRequest request, Object mdmsData) { - PlanConfiguration planConfiguration = request.getPlanConfiguration(); - List files = planConfiguration.getFiles(); - List templateIds = files.stream() - .map(File::getTemplateIdentifier) - .collect(Collectors.toList()); - List inputFileTypes = files.stream() - .map(File::getInputFileType) - .map(File.InputFileTypeEnum::toString) - .collect(Collectors.toList()); - - final String jsonPathForRuleInputs = JSON_ROOT_PATH + MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_MASTER_SCHEMAS; - List ruleInputsListFromMDMS = null; - try { - log.info(jsonPathForRuleInputs); - ruleInputsListFromMDMS = JsonPath.read(mdmsData, jsonPathForRuleInputs); - } catch (Exception e) { - log.error(e.getMessage()); - throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); - } - - HashSet ruleInputsSetFromMDMS = new HashSet<>(ruleInputsListFromMDMS); - - HashSet allowedColumns = getColumnsFromSchemaThatAreRuleInputs(ruleInputsSetFromMDMS, templateIds, inputFileTypes); - planConfiguration.getOperations().stream() - .map(Operation::getOutput) - .forEach(allowedColumns::add); - - planConfiguration.getOperations().stream().forEach(operation -> { - if (!allowedColumns.contains(operation.getInput())) { - log.error("Input Value " + operation.getInput() + " is not present in MDMS Input List"); - throw new CustomException(INPUT_KEY_NOT_FOUND_CODE, INPUT_KEY_NOT_FOUND_MESSAGE); } - }); - - } - /** - * Filters the Schema MDMS data by type and section - * returns the list of columns which have the property 'isRuleConfigureInputs' as true - * - * @param schemas List of schemas from MDMS - * @param templateIds The list of template identifiers from request object - * @param inputFileTypes The list of input file type from request object - */ - public static HashSet getColumnsFromSchemaThatAreRuleInputs(HashSet schemas, List templateIds, List inputFileTypes) { - if (schemas == null) { - return new HashSet<>(); } - HashSet finalData = new HashSet<>(); - for (Object item : schemas) { - LinkedHashMap schemaEntity = (LinkedHashMap) item; - if(!templateIds.contains(schemaEntity.get(MDMS_SCHEMA_SECTION)) || !inputFileTypes.contains(schemaEntity.get(MDMS_SCHEMA_TYPE))) continue; - LinkedHashMap columns = (LinkedHashMap)((LinkedHashMap) schemaEntity.get(MDMS_SCHEMA_SCHEMA)).get(MDMS_SCHEMA_PROPERTIES); - if(columns == null) return new HashSet<>(); - columns.entrySet().stream() - .forEach(column -> { - LinkedHashMap data = column.getValue(); - if(data.get(MDMS_SCHEMA_PROPERTIES_IS_RULE_CONFIGURE_INPUT)){ - finalData.add(column.getKey()); - } - }); // Add the keys to finalData - } - return finalData; } - - /** - * Validates that the 'mappedTo' values in the list of 'resourceMappings' are unique. - * If a duplicate 'mappedTo' value is found, it logs an error and throws a CustomException. - * - * @param resourceMappings The list of 'ResourceMapping' objects to validate. - * @throws CustomException If a duplicate 'mappedTo' value is found. - */ - public static void validateMappedToUniqueness(List resourceMappings) { - Set uniqueMappedToSet = new HashSet<>(); - resourceMappings.stream().forEach(mapping -> { - String uniqueKey = mapping.getFilestoreId() + "-" + mapping.getMappedTo(); - if (!uniqueMappedToSet.add(uniqueKey)) { - log.error("Duplicate MappedTo " + mapping.getMappedTo() + " for FilestoreId " + mapping.getFilestoreId()); - throw new CustomException(DUPLICATE_MAPPED_TO_VALIDATION_ERROR_CODE, DUPLICATE_MAPPED_TO_VALIDATION_ERROR_MESSAGE + " - " + mapping.getMappedTo() + " for FilestoreId " + mapping.getFilestoreId()); - } - }); - } - - /** * Validates the search request for plan configurations. + * * @param planConfigurationSearchRequest The search request for plan configurations. */ public void validateSearchRequest(PlanConfigurationSearchRequest planConfigurationSearchRequest) { @@ -360,62 +295,60 @@ private void validateSearchCriteria(PlanConfigurationSearchRequest planConfigura /** * Validates the update request for plan configuration, including assumptions against MDMS data. + * * @param request The update request for plan configuration. */ public void validateUpdateRequest(PlanConfigurationRequest request) { PlanConfiguration planConfiguration = request.getPlanConfiguration(); String rootTenantId = centralInstanceUtil.getStateLevelTenant(planConfiguration.getTenantId()); Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), rootTenantId); + List mdmsV2Data = mdmsV2Util.fetchMdmsV2Data(request.getRequestInfo(), rootTenantId, MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_SCHEMA_VEHICLE_DETAILS, null); + CampaignResponse campaignResponse = campaignUtil.fetchCampaignData(request.getRequestInfo(), request.getPlanConfiguration().getCampaignId(), rootTenantId); // Validate the existence of the plan configuration in the request validatePlanConfigExistence(request); + // Validate if campaign id exists against project factory + validateCampaignId(campaignResponse); + // Validate that the assumption keys in the request are present in the MDMS data validateAssumptionKeyAgainstMDMS(request, mdmsData); - // Validate that the assumption values in the plan configuration are correct - validateAssumptionValue(planConfiguration); + // Validate that the assumption keys in the request are unique + validateAssumptionUniqueness(planConfiguration); - // Validate the filestore ID in the plan configuration's request mappings - validateFilestoreId(planConfiguration); + //Validating operation's input and assumptionValue fields + validateOperations(request, campaignResponse); // Validate that the template identifiers in the request match those in the MDMS data validateTemplateIdentifierAgainstMDMS(request, mdmsData); - // Validate that the inputs for operations in the request match those in the MDMS data - validateOperationsInputAgainstMDMS(request, mdmsData); - - // Validate the dependencies between operations in the plan configuration - validateOperationDependencies(planConfiguration); - - // Validate that the resource mappings in the request match those in the MDMS data - validateResourceMappingAgainstMDMS(request, mdmsData); - - // Validate the uniqueness of the 'mappedTo' fields in the resource mappings - validateMappedToUniqueness(planConfiguration.getResourceMapping()); - //Validating plan config name against MDMS data validatePlanConfigName(request, mdmsData); // Validate the user information in the request - validateUserInfo(request); + commonUtil.validateUserInfo(request.getRequestInfo()); + + // Validates the vehicle id from additional details object against the data from mdms v2 + validateVehicleIdsFromAdditionalDetailsAgainstMDMS(request, mdmsV2Data); + } /** * Validates the existence of the plan configuration in the repository. + * * @param request The request containing the plan configuration to validate. */ - public PlanConfiguration validatePlanConfigExistence(PlanConfigurationRequest request) { + public void validatePlanConfigExistence(PlanConfigurationRequest request) { // If plan id provided is invalid, throw an exception List planConfigurationList = planConfigRepository.search(PlanConfigurationSearchCriteria.builder() .id(request.getPlanConfiguration().getId()) .build()); - if(CollectionUtils.isEmpty(planConfigurationList)) { + if (CollectionUtils.isEmpty(planConfigurationList)) { throw new CustomException(INVALID_PLAN_CONFIG_ID_CODE, INVALID_PLAN_CONFIG_ID_MESSAGE); } - return planConfigurationList.get(0); } /** @@ -426,103 +359,231 @@ public PlanConfiguration validatePlanConfigExistence(PlanConfigurationRequest re * @throws CustomException If an inactive operation's output is used as input in any other active operation. */ public static void validateOperationDependencies(PlanConfiguration planConfiguration) { - // Collect all active operations' inputs - Set activeInputs = planConfiguration.getOperations().stream() - .filter(Operation::getActive) - .map(Operation::getInput) - .collect(Collectors.toSet()); + if (!CollectionUtils.isEmpty(planConfiguration.getOperations())) { + // Collect all active operations' inputs + Set activeInputs = planConfiguration.getOperations().stream() + .filter(Operation::getActive) + .map(Operation::getInput) + .collect(Collectors.toSet()); + + // Check for each inactive operation + planConfiguration.getOperations().forEach(operation -> { + if (!operation.getActive() && activeInputs.contains(operation.getOutput())) { + log.error(INACTIVE_OPERATION_USED_AS_INPUT_MESSAGE + operation.getOutput()); + throw new CustomException(INACTIVE_OPERATION_USED_AS_INPUT_CODE, INACTIVE_OPERATION_USED_AS_INPUT_MESSAGE + operation.getOutput()); + } + }); + } + } - // Check for each inactive operation - planConfiguration.getOperations().stream().forEach(operation -> { - if (!operation.getActive() && activeInputs.contains(operation.getOutput())) { - log.error(INACTIVE_OPERATION_USED_AS_INPUT_MESSAGE + operation.getOutput()); - throw new CustomException(INACTIVE_OPERATION_USED_AS_INPUT_CODE, INACTIVE_OPERATION_USED_AS_INPUT_MESSAGE + operation.getOutput()); - } - }); + + /** + * Validates Vehicle ids from additional details against MDMS V2 + * + * @param request plan configuration request + * @param mdmsV2Data mdms v2 data object + */ + public void validateVehicleIdsFromAdditionalDetailsAgainstMDMS(PlanConfigurationRequest request, List mdmsV2Data) { + List vehicleIdsfromAdditionalDetails = commonUtil.extractFieldsFromJsonObject(request.getPlanConfiguration().getAdditionalDetails(), JSON_FIELD_VEHICLE_ID, List.class); + if (!CollectionUtils.isEmpty(vehicleIdsfromAdditionalDetails)) { + List vehicleIdsFromMdms = mdmsV2Data.stream() + .map(Mdms::getId) + .toList(); + + vehicleIdsfromAdditionalDetails.forEach(vehicleId -> { + if (!vehicleIdsFromMdms.contains(vehicleId)) { + log.error("Vehicle Id " + vehicleId + " is not present in MDMS"); + throw new CustomException(VEHICLE_ID_NOT_FOUND_IN_MDMS_CODE, VEHICLE_ID_NOT_FOUND_IN_MDMS_MESSAGE); + } + }); + } } - /** - * Validate input (BCode) against MDMS data. - * @param request plan configauration request. - * @param mdmsData MDMS data object. - */ - public void validateResourceMappingAgainstMDMS(PlanConfigurationRequest request, Object mdmsData) { - PlanConfiguration planConfiguration = request.getPlanConfiguration(); - List files = planConfiguration.getFiles(); - List templateIds = files.stream() - .map(File::getTemplateIdentifier) - .toList(); - List inputFileTypes = files.stream() - .map(File::getInputFileType) - .map(File.InputFileTypeEnum::toString) - .toList(); - - final String jsonPathForRuleInputs = JSON_ROOT_PATH + MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_MASTER_SCHEMAS; - List ruleInputsListFromMDMS = null; - try { - log.info(jsonPathForRuleInputs); - ruleInputsListFromMDMS = JsonPath.read(mdmsData, jsonPathForRuleInputs); - } catch (Exception e) { - log.error(e.getMessage()); - throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); + /** + * Checks if files are empty or null when the setup action is marked as completed. + * + * @param planConfiguration The plan configuration to check. + */ + private void checkForEmptyFiles(PlanConfiguration planConfiguration) { + if (CollectionUtils.isEmpty(planConfiguration.getFiles())) { + log.error("Files cannot be empty at action = " + SETUP_COMPLETED_ACTION); + throw new CustomException(FILES_NOT_FOUND_CODE, FILES_NOT_FOUND_MESSAGE); } - HashSet ruleInputsSetFromMDMS = new HashSet<>(ruleInputsListFromMDMS); - HashSet requiredColumns = getRequiredColumnsFromSchema(ruleInputsSetFromMDMS, templateIds, inputFileTypes); - List resourceMappings = planConfiguration.getResourceMapping(); + } - // Throw a custom exception if no active mappings with BOUNDARY_CODE are found - if(requiredColumns.contains(ServiceConstants.BOUNDARY_CODE)) { - boolean exists = resourceMappings.stream() - .anyMatch(mapping -> mapping.getActive() && mapping.getMappedTo().equals(ServiceConstants.BOUNDARY_CODE)); + /** + * Checks if assumptions are empty or null when the setup action is marked as completed. + * + * @param planConfiguration The plan configuration to check. + */ + private void checkForEmptyAssumption(PlanConfiguration planConfiguration) { + if (CollectionUtils.isEmpty(planConfiguration.getAssumptions())) { + log.error("Assumptions cannot be empty at action = " + SETUP_COMPLETED_ACTION); + throw new CustomException(ASSUMPTIONS_NOT_FOUND_CODE, ASSUMPTIONS_NOT_FOUND_MESSAGE); + } + } - if (!exists) { - throw new CustomException(BOUNDARY_CODE_MAPPING_NOT_FOUND_CODE, BOUNDARY_CODE_MAPPING_NOT_FOUND_MESSAGE); - } + /** + * Checks if operations are empty or null when the setup action is marked as completed. + * + * @param planConfiguration The plan configuration to check. + */ + private void checkForEmptyOperation(PlanConfiguration planConfiguration) { + if (CollectionUtils.isEmpty(planConfiguration.getOperations())) { + log.error("Operations cannot be empty at action = " + SETUP_COMPLETED_ACTION); + throw new CustomException(OPERATIONS_NOT_FOUND_CODE, OPERATIONS_NOT_FOUND_MESSAGE); } + } + + /** + * Validates the inputs and assumption values in the plan configuration after verifying the setup action is completed. + * + * @param request The plan configuration request to validate. + * @param campaignResponse The campaign response containing details for validation. + */ + public void validateOperations(PlanConfigurationRequest request, CampaignResponse campaignResponse) { + PlanConfiguration planConfiguration = request.getPlanConfiguration(); + + if (commonUtil.isSetupCompleted(planConfiguration)) { + performEmptyChecks(planConfiguration); + + // Get shared data upfront + HashSet allowedColumns = getAllowedColumnsFromMDMS( + request, campaignResponse.getCampaignDetails().get(0).getProjectType() + ); + Set activeAssumptionKeys = getActiveAssumptionKeys(planConfiguration); + validateOperationInputs(planConfiguration, allowedColumns, activeAssumptionKeys); + validateOperationAssumptionValues(planConfiguration, allowedColumns, activeAssumptionKeys); } + } + + /** + * Performs checks for empty files, assumptions, and operations in the plan configuration. + * + * @param planConfiguration The plan configuration to check. + */ + private void performEmptyChecks(PlanConfiguration planConfiguration) { + checkForEmptyFiles(planConfiguration); + checkForEmptyOperation(planConfiguration); + checkForEmptyAssumption(planConfiguration); + } /** - * Filters the Schema MDMS data by type and section - * returns the list of columns which have the property 'isRequired' as true + * Retrieves allowed columns based on MDMS data and campaign type. * - * @param schemas List of schemas from MDMS - * @param templateIds The list of template identifiers from request object - * @param inputFileTypes The list of input file type from request object - * @return List of Columns that are required + * @param request The plan configuration request containing tenant information. + * @param campaignType The type of campaign for which allowed columns are fetched. + * @return A set of allowed column names. */ - public static HashSet getRequiredColumnsFromSchema(HashSet schemas, List templateIds, List inputFileTypes) { - if (CollectionUtils.isEmpty(schemas)) { - return new HashSet<>(); + private HashSet getAllowedColumnsFromMDMS(PlanConfigurationRequest request, String campaignType) { + String rootTenantId = centralInstanceUtil.getStateLevelTenant(request.getPlanConfiguration().getTenantId()); + String uniqueIndentifier = BOUNDARY + DOT_SEPARATOR + MICROPLAN_PREFIX + campaignType; + List mdmsV2Data = mdmsV2Util.fetchMdmsV2Data(request.getRequestInfo(), rootTenantId, MDMS_ADMIN_CONSOLE_MODULE_NAME + DOT_SEPARATOR + MDMS_SCHEMA_ADMIN_SCHEMA, uniqueIndentifier); + List columnNameList = extractPropertyNamesFromAdminSchema(mdmsV2Data.get(0).getData()); + return new HashSet<>(columnNameList); + } + + /** + * Extracts the names of properties defined within the "numberProperties" and "stringProperties" arrays from admin schema. + * + * @param rootNode The root JSON node from which to extract property names. + * @return A list of property names found in "numberProperties" and "stringProperties". + */ + public List extractPropertyNamesFromAdminSchema(JsonNode rootNode) { + List names = new ArrayList<>(); + + // Access the "properties" node directly from the root node + JsonNode propertiesNode = rootNode.path(PROPERTIES); + + // Extract names from "numberProperties" + JsonNode numberProperties = propertiesNode.path(NUMBER_PROPERTIES); + if (numberProperties.isArray()) { + for (JsonNode property : numberProperties) { + String name = property.path(NAME).asText(null); + if (name != null) { + names.add(name); + } + } } - HashSet finalData = new HashSet<>(); - for (Object item : schemas) { - LinkedHashMap schemaEntity = (LinkedHashMap) item; - if(!templateIds.contains(schemaEntity.get(MDMS_SCHEMA_SECTION)) || !inputFileTypes.contains(schemaEntity.get(MDMS_SCHEMA_TYPE))) continue; - LinkedHashMap columns = (LinkedHashMap)((LinkedHashMap) schemaEntity.get(MDMS_SCHEMA_SCHEMA)).get(MDMS_SCHEMA_PROPERTIES); - if (columns == null) return new HashSet<>(); - columns.entrySet().stream().forEach(column -> { - LinkedHashMap data = column.getValue(); - if (data.get(MDMS_SCHEMA_PROPERTIES_IS_REQUIRED)) { - finalData.add(column.getKey()); + + // Extract names from "stringProperties" + JsonNode stringProperties = propertiesNode.path(STRING_PROPERTIES); + if (stringProperties.isArray()) { + for (JsonNode property : stringProperties) { + String name = property.path(NAME).asText(null); + if (name != null) { + names.add(name); } - }); + } + } + + return names; + } + + /** + * Gets keys of active assumptions in the plan configuration. + * + * @param planConfiguration The plan configuration containing assumptions. + * @return A set of keys of active assumptions. + */ + private Set getActiveAssumptionKeys(PlanConfiguration planConfiguration) { + return planConfiguration.getAssumptions().stream() + .filter(Assumption::getActive) + .map(Assumption::getKey) + .collect(Collectors.toSet()); + } + + /** + * Validates the input values of operations against allowed columns and previous outputs. + * + * @param planConfiguration The plan configuration containing operations. + * @param allowedColumns The allowed column names for input validation. + */ + private void validateOperationInputs(PlanConfiguration planConfiguration, HashSet allowedColumns, Set activeAssumptionKeys) { + // Set to keep track of previous outputs + Set previousOutputs = new HashSet<>(); + + for (Operation operation : planConfiguration.getOperations()) { + // Validate input + if (operation.getActive() && !allowedColumns.contains(operation.getInput()) && !activeAssumptionKeys.contains(operation.getInput()) && !previousOutputs.contains(operation.getInput()) && operation.getSource() == Source.MDMS) { + log.error("Input Value " + operation.getInput() + " is not present in allowed columns or previous outputs"); + throw new CustomException(INPUT_KEY_NOT_FOUND_CODE, INPUT_KEY_NOT_FOUND_MESSAGE + operation.getInput()); + } + + // Add current operation's output to previousOutputs if it's active + if (operation.getActive()) { + previousOutputs.add(operation.getOutput()); + } } - return finalData; } /** - * Validates the user information within the provided PlanConfigurationRequest. + * Validates the assumption values of operations against allowed columns, active keys, and previous outputs. * - * @param request the PlanConfigurationRequest containing the user information to be validated - * @throws CustomException if the user information is missing in the request + * @param planConfiguration The plan configuration containing operations. + * @param allowedColumns The allowed column names for assumption validation. + * @param activeAssumptionKeys The set of active assumption keys. */ - public void validateUserInfo(PlanConfigurationRequest request) - { - if (ObjectUtils.isEmpty(request.getRequestInfo().getUserInfo())) { - log.error(USERINFO_MISSING_MESSAGE); - throw new CustomException(USERINFO_MISSING_CODE, USERINFO_MISSING_MESSAGE); + private void validateOperationAssumptionValues(PlanConfiguration planConfiguration, HashSet allowedColumns, Set activeAssumptionKeys) { + // Set to keep track of previous outputs + Set previousOutputs = new HashSet<>(); + + for (Operation operation : planConfiguration.getOperations()) { + String assumptionValue = operation.getAssumptionValue(); + + // Validate assumption value + if (operation.getActive() && !allowedColumns.contains(assumptionValue) && !activeAssumptionKeys.contains(assumptionValue) && !previousOutputs.contains(assumptionValue) && operation.getSource() == Source.MDMS) { + log.error("Assumption Value " + assumptionValue + " is not present in allowed columns, previous outputs, or active Assumption Keys"); + throw new CustomException(ASSUMPTION_VALUE_NOT_FOUND_CODE, ASSUMPTION_VALUE_NOT_FOUND_MESSAGE + " - " + assumptionValue); + } + + // Add current operation's output to previousOutputs if it's active + if (operation.getActive() && operation.getSource() == Source.MDMS) { + previousOutputs.add(operation.getOutput()); + } } } + } diff --git a/health-services/plan-service/src/main/java/digit/service/validator/PlanEmployeeAssignmentValidator.java b/health-services/plan-service/src/main/java/digit/service/validator/PlanEmployeeAssignmentValidator.java new file mode 100644 index 00000000000..772ec6dd133 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/validator/PlanEmployeeAssignmentValidator.java @@ -0,0 +1,349 @@ +package digit.service.validator; + +import digit.config.Configuration; +import digit.repository.PlanEmployeeAssignmentRepository; +import digit.util.*; +import digit.web.models.*; +import digit.web.models.projectFactory.Boundary; +import digit.web.models.projectFactory.CampaignDetail; +import digit.web.models.projectFactory.CampaignResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.Role; +import org.egov.common.contract.user.UserDetailResponse; +import org.egov.common.utils.MultiStateInstanceUtil; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.*; + +import java.util.*; +import java.util.stream.Collectors; + +import static digit.config.ServiceConstants.*; + +@Slf4j +@Component +public class PlanEmployeeAssignmentValidator { + + private MultiStateInstanceUtil centralInstanceUtil; + + private MdmsUtil mdmsUtil; + + private UserUtil userUtil; + + private CommonUtil commonUtil; + + private CampaignUtil campaignUtil; + + private PlanEmployeeAssignmentRepository repository; + + private Configuration config; + + public PlanEmployeeAssignmentValidator(MultiStateInstanceUtil centralInstanceUtil, MdmsUtil mdmsUtil, UserUtil userUtil, CommonUtil commonUtil, CampaignUtil campaignUtil, PlanEmployeeAssignmentRepository repository, Configuration config) { + this.centralInstanceUtil = centralInstanceUtil; + this.mdmsUtil = mdmsUtil; + this.userUtil = userUtil; + this.commonUtil = commonUtil; + this.campaignUtil = campaignUtil; + this.repository = repository; + this.config = config; + } + + /** + * This method validates the create request for plan employee assignment. + * + * @param request The create request for plan employee assignment + */ + public void validateCreate(PlanEmployeeAssignmentRequest request) { + PlanEmployeeAssignment planEmployeeAssignment = request.getPlanEmployeeAssignment(); + String rootTenantId = centralInstanceUtil.getStateLevelTenant(request.getPlanEmployeeAssignment().getTenantId()); + List planConfigurations = commonUtil.searchPlanConfigId(planEmployeeAssignment.getPlanConfigurationId(), rootTenantId); + UserDetailResponse userDetailResponse = userUtil.fetchUserDetail(userUtil.getUserSearchReq(request.getRequestInfo(), planEmployeeAssignment.getEmployeeId(), planEmployeeAssignment.getTenantId())); + + // Validate if a same assignment already exists + validateDuplicateRecord(request); + + // Validate if plan config id exists + validatePlanConfigId(planConfigurations); + + // Validate role of employee against User Service + validateRoleAgainstUserService(planEmployeeAssignment, userDetailResponse); + + // Validate if role of employee is a conflicting role + validateRoleConflict(planEmployeeAssignment); + + // Validate campaign id, employee jurisdiction and highest root jurisdiction in case of Root role + validateCampaignDetails(planConfigurations.get(0).getCampaignId(), rootTenantId, request); + + } + + /** + * This method validates the provided roles of the employee against User Service + * + * @param planEmployeeAssignment The plan employee assignment provided in request + * @param userDetailResponse The user detail response from user service for the provided employeeId + */ + private void validateRoleAgainstUserService(PlanEmployeeAssignment planEmployeeAssignment, UserDetailResponse userDetailResponse) { + + // Validate if employee exists against User Service + if (CollectionUtils.isEmpty(userDetailResponse.getUser())) { + throw new CustomException(INVALID_EMPLOYEE_ID_CODE, INVALID_EMPLOYEE_ID_MESSAGE); + } + + List userRolesFromUserService = userDetailResponse.getUser().get(0).getRoles().stream() + .map(Role::getCode) + .toList(); + + if (!userRolesFromUserService.contains(planEmployeeAssignment.getRole())) { + throw new CustomException(INVALID_EMPLOYEE_ROLE_CODE, INVALID_EMPLOYEE_ROLE_MESSAGE); + } + } + + /** + * Validates if the plan employee assignment for the provided details already exists + * + * @param request the employee assignment create request + */ + private void validateDuplicateRecord(PlanEmployeeAssignmentRequest request) { + PlanEmployeeAssignment employeeAssignment = request.getPlanEmployeeAssignment(); + + List planEmployeeAssignmentsFromSearch = repository.search(PlanEmployeeAssignmentSearchCriteria.builder() + .tenantId(employeeAssignment.getTenantId()) + .planConfigurationId(employeeAssignment.getPlanConfigurationId()) + .employeeId(Collections.singletonList(employeeAssignment.getEmployeeId())) + .role(Collections.singletonList(employeeAssignment.getRole())) + .build()); + + if (!CollectionUtils.isEmpty(planEmployeeAssignmentsFromSearch)) { + throw new CustomException(PLAN_EMPLOYEE_ASSIGNMENT_ALREADY_EXISTS_CODE, PLAN_EMPLOYEE_ASSIGNMENT_ALREADY_EXISTS_MESSAGE); + } + } + + /** + * Validates that employee with National role is assigned to the highest root jurisdiction only against MDMS + * + * @param planEmployeeAssignment The plan employee assignment provided in request + * @param mdmsData mdms data from mdms v2 + * @param campaignDetail the campaign details for the corresponding campaign id + */ + private void validateRootEmployeeJurisdiction(PlanEmployeeAssignment planEmployeeAssignment, Object mdmsData, CampaignDetail campaignDetail) { + if (planEmployeeAssignment.getRole().contains(ROOT_PREFIX)) { + Set jurisdiction = planEmployeeAssignment.getJurisdiction(); + + // Validate that National role employee should not have more than one jurisdiction assigned + if (jurisdiction.size() > 1) { + throw new CustomException(INVALID_ROOT_EMPLOYEE_JURISDICTION_CODE, INVALID_ROOT_EMPLOYEE_JURISDICTION_MESSAGE); + } + + String rootLevelJurisdiction = jurisdiction.stream().findFirst().orElse(null); + + // Fetch the highest hierarchy for Microplan from MDMS + String highestHierarchy = commonUtil.getMicroplanHierarchy(mdmsData).get(HIGHEST_HIERARCHY_FIELD_FOR_MICROPLAN); + + // Filter out the boundary details for the jurisdiction assigned to employee + // Throw exception if jurisdiction assigned to Root role employee is not the highest hierarchy + campaignDetail.getBoundaries().stream() + .filter(boundary -> boundary.getCode().equals(rootLevelJurisdiction)) + .forEach(boundary -> { + if (!boundary.getType().toLowerCase().equals(highestHierarchy)) { + throw new CustomException(INVALID_ROOT_EMPLOYEE_JURISDICTION_CODE, INVALID_ROOT_EMPLOYEE_JURISDICTION_MESSAGE); + } + }); + } + } + + /** + * This method checks if the employee's role provided is a conflicting role against the role map. + * + * @param planEmployeeAssignment The plan employee assignment provided in request + */ + private void validateRoleConflict(PlanEmployeeAssignment planEmployeeAssignment) { + + // Fetch the role mappings from the configuration + Map roleMap = config.getRoleMap(); + + // Check if the role of the employee exists in the role map + if (roleMap.containsKey(planEmployeeAssignment.getRole())) { + + // Fetch existing role assignments for the employee based on their tenant, planConfig Id, and employee ID + // The search is conducted using the conflicting role + List response = repository.search(PlanEmployeeAssignmentSearchCriteria.builder() + .tenantId(planEmployeeAssignment.getTenantId()) + .planConfigurationId(planEmployeeAssignment.getPlanConfigurationId()) + .employeeId(Collections.singletonList(planEmployeeAssignment.getEmployeeId())) + .role(Collections.singletonList(roleMap.get(planEmployeeAssignment.getRole()))).build()); + + // If there are any conflicting assignments found, throw a custom exception + if (!CollectionUtils.isEmpty(response)) { + throw new CustomException(INVALID_EMPLOYEE_ROLE_CODE, INVALID_EMPLOYEE_ROLE_MESSAGE); + } + } + } + + /** + * This method validates campaign id and employee's jurisdiction against project factory + * If the employee has a national role, it validates that the employee has the highest root jurisdiction only + * + * @param campaignId the campaign id corresponding to the plan config id provided in the request + * @param tenantId the tenant id provided in the request + * @param planEmployeeAssignmentRequest the plan employee assignment request provided + */ + private void validateCampaignDetails(String campaignId, String tenantId, PlanEmployeeAssignmentRequest planEmployeeAssignmentRequest) { + PlanEmployeeAssignment planEmployeeAssignment = planEmployeeAssignmentRequest.getPlanEmployeeAssignment(); + CampaignResponse campaignResponse = campaignUtil.fetchCampaignData(planEmployeeAssignmentRequest.getRequestInfo(), campaignId, tenantId); + Object mdmsData = mdmsUtil.fetchMdmsData(planEmployeeAssignmentRequest.getRequestInfo(), tenantId); + + // Validate if campaign id exists against project factory + validateCampaignId(campaignResponse); + + // Validate the provided jurisdiction for the plan employee assignment + validateEmployeeAssignmentJurisdiction(campaignResponse.getCampaignDetails().get(0), planEmployeeAssignment); + + // Validates the jurisdiction assigned to Root role employee against MDMS + validateRootEmployeeJurisdiction(planEmployeeAssignment, mdmsData, campaignResponse.getCampaignDetails().get(0)); + + // Validates the jurisdiction assigned to a non-Root employee against MDMS + validateEmployeeJurisdiction(planEmployeeAssignment, mdmsData, campaignResponse.getCampaignDetails().get(0)); + } + + /** + * Validates that a non-Root role employee is not assigned to the highest or lowest hierarchy against MDMS + * + * @param planEmployeeAssignment The plan employee assignment provided in request + * @param mdmsData mdms data from mdms v2 + * @param campaignDetail the campaign details for the corresponding campaign id + */ + private void validateEmployeeJurisdiction(PlanEmployeeAssignment planEmployeeAssignment, Object mdmsData, CampaignDetail campaignDetail) { + if (!planEmployeeAssignment.getRole().contains(ROOT_PREFIX)) { + Set jurisdiction = planEmployeeAssignment.getJurisdiction(); + + // Fetch the highest and lowest hierarchy for Microplan from MDMS + Map hierarchyMap = commonUtil.getMicroplanHierarchy(mdmsData); + String lowestHierarchy = hierarchyMap.get(LOWEST_HIERARCHY_FIELD_FOR_MICROPLAN); + String highestHierarchy = hierarchyMap.get(HIGHEST_HIERARCHY_FIELD_FOR_MICROPLAN); + + // Filter out the boundary details for the jurisdiction assigned to employee + // Simultaneously validating if employee is assigned to lowest or highest hierarchy + campaignDetail.getBoundaries().stream() + .filter(boundary -> jurisdiction.contains(boundary.getCode())) + .forEach(boundary -> { + if (boundary.getType().toLowerCase().equals(lowestHierarchy) || + boundary.getType().toLowerCase().equals(highestHierarchy)) { + throw new CustomException(INVALID_EMPLOYEE_JURISDICTION_CODE, INVALID_EMPLOYEE_JURISDICTION_MESSAGE); + } + }); + } + } + + /** + * This method validates if employee's jurisdiction exist in campaign details + * + * @param campaignDetail the campaign details for the corresponding campaign id + * @param planEmployeeAssignment the plan employee assignment provided in request + */ + private void validateEmployeeAssignmentJurisdiction(CampaignDetail campaignDetail, PlanEmployeeAssignment planEmployeeAssignment) { + + // Collect all boundary code for the campaign + Set boundaryCode = campaignDetail.getBoundaries().stream() + .filter(boundary -> planEmployeeAssignment.getHierarchyLevel().equals(boundary.getType())) + .map(Boundary::getCode) + .collect(Collectors.toSet()); + + if(CollectionUtils.isEmpty(boundaryCode)) { + throw new CustomException(INVALID_HIERARCHY_LEVEL_CODE, INVALID_HIERARCHY_LEVEL_MESSAGE); + } + + planEmployeeAssignment.getJurisdiction() + .forEach(jurisdiction -> { + if (!boundaryCode.contains(jurisdiction)) { + throw new CustomException(INVALID_JURISDICTION_CODE, INVALID_JURISDICTION_MESSAGE); + } + }); + + } + + /** + * This method validates if the campaign id provided in the request exists + * + * @param campaignResponse The campaign details response from project factory + */ + private void validateCampaignId(CampaignResponse campaignResponse) { + if (CollectionUtils.isEmpty(campaignResponse.getCampaignDetails())) { + throw new CustomException(NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_CODE, NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_MESSAGE); + } + } + + /** + * This method validates if the plan configuration id provided in the request exists + * + * @param planConfigurations The list of plan configuration for the provided plan config id + */ + private void validatePlanConfigId(List planConfigurations) { + if (CollectionUtils.isEmpty(planConfigurations)) { + throw new CustomException(INVALID_PLAN_CONFIG_ID_CODE, INVALID_PLAN_CONFIG_ID_MESSAGE); + } + } + + /** + * Validates the search request for plan employee assignment + * + * @param request the request to search plan employee assignment + */ + public void validateSearch(PlanEmployeeAssignmentSearchRequest request) { + PlanEmployeeAssignmentSearchCriteria searchCriteria = request.getPlanEmployeeAssignmentSearchCriteria(); + if (Objects.isNull(searchCriteria)) { + throw new CustomException(SEARCH_CRITERIA_EMPTY_CODE, SEARCH_CRITERIA_EMPTY_MESSAGE); + } + + if (StringUtils.isEmpty(searchCriteria.getTenantId())) { + throw new CustomException(TENANT_ID_EMPTY_CODE, TENANT_ID_EMPTY_MESSAGE); + } + + if (StringUtils.isEmpty(searchCriteria.getPlanConfigurationId())) { + throw new CustomException(PLAN_CONFIG_ID_EMPTY_CODE, PLAN_CONFIG_ID_EMPTY_MESSAGE); + } + } + + /** + * This method validates the update request for plan employee assignment. + * + * @param request The update request for plan employee assignment. + */ + public void validateUpdate(PlanEmployeeAssignmentRequest request) { + PlanEmployeeAssignment planEmployeeAssignment = request.getPlanEmployeeAssignment(); + String rootTenantId = centralInstanceUtil.getStateLevelTenant(request.getPlanEmployeeAssignment().getTenantId()); + List planConfigurations = commonUtil.searchPlanConfigId(planEmployeeAssignment.getPlanConfigurationId(), rootTenantId); + + // Validate if Plan employee assignment exists + validatePlanEmployeeAssignmentExistance(planEmployeeAssignment); + + // Validate campaign id and employee jurisdiction + validateCampaignDetails(planConfigurations.get(0).getCampaignId(), rootTenantId, request); + + } + + /** + * This method validates if the plan employee assignment provided in the update request exists + * + * @param planEmployeeAssignment The plan employee assignment details from the request + */ + private void validatePlanEmployeeAssignmentExistance(PlanEmployeeAssignment planEmployeeAssignment) { + if (ObjectUtils.isEmpty(planEmployeeAssignment.getId())) { + throw new CustomException(PLAN_EMPLOYEE_ASSIGNMENT_ID_EMPTY_CODE, PLAN_EMPLOYEE_ASSIGNMENT_ID_EMPTY_MESSAGE); + } + + // Validates the existence of plan employee assignment + List planEmployeeAssignments = repository.search(PlanEmployeeAssignmentSearchCriteria.builder() + .tenantId(planEmployeeAssignment.getTenantId()) + .id(planEmployeeAssignment.getId()) + .role(Collections.singletonList(planEmployeeAssignment.getRole())) + .planConfigurationId(planEmployeeAssignment.getPlanConfigurationId()) + .employeeId(Collections.singletonList(planEmployeeAssignment.getEmployeeId())) + .build()); + + if (CollectionUtils.isEmpty(planEmployeeAssignments)) { + throw new CustomException(INVALID_PLAN_EMPLOYEE_ASSIGNMENT_CODE, INVALID_PLAN_EMPLOYEE_ASSIGNMENT_MESSAGE); + } + } + +} diff --git a/health-services/plan-service/src/main/java/digit/service/validator/PlanFacilityValidator.java b/health-services/plan-service/src/main/java/digit/service/validator/PlanFacilityValidator.java new file mode 100644 index 00000000000..dd7b251eaf1 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/validator/PlanFacilityValidator.java @@ -0,0 +1,301 @@ +package digit.service.validator; + +import com.jayway.jsonpath.JsonPath; +import digit.repository.PlanConfigurationRepository; +import digit.repository.PlanFacilityRepository; +import digit.service.enrichment.PlanFacilityEnricher; +import digit.util.*; +import digit.web.models.*; +import digit.web.models.facility.Facility; +import digit.web.models.facility.FacilityResponse; +import digit.web.models.projectFactory.CampaignDetail; +import digit.web.models.projectFactory.CampaignResponse; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.utils.MultiStateInstanceUtil; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import static digit.config.ServiceConstants.*; + +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +import digit.web.models.projectFactory.Boundary; + +@Component +@Slf4j +public class PlanFacilityValidator { + private PlanFacilityRepository planFacilityRepository; + private PlanConfigurationRepository planConfigurationRepository; + private CampaignUtil campaignUtil; + private MultiStateInstanceUtil centralInstanceUtil; + private MdmsUtil mdmsUtil; + private FacilityUtil facilityUtil; + private CommonUtil commonUtil; + private PlanFacilityEnricher enrichment; + + public PlanFacilityValidator(PlanFacilityRepository planFacilityRepository, PlanConfigurationRepository planConfigurationRepository, CampaignUtil campaignUtil, MultiStateInstanceUtil centralInstanceUtil, MdmsUtil mdmsUtil, FacilityUtil facilityUtil, CommonUtil commonUtil, PlanFacilityEnricher enrichment) { + this.planFacilityRepository = planFacilityRepository; + this.planConfigurationRepository = planConfigurationRepository; + this.campaignUtil = campaignUtil; + this.centralInstanceUtil = centralInstanceUtil; + this.mdmsUtil = mdmsUtil; + this.facilityUtil = facilityUtil; + this.commonUtil = commonUtil; + this.enrichment = enrichment; + } + + /** + * This method validates the Plan Facility Create request. + * It performs multiple validations such as plan configuration, facility existence, + * and campaign-related validations. + * + * @param planFacilityRequest + */ + public void validatePlanFacilityCreate(@Valid PlanFacilityRequest planFacilityRequest) { + // Retrieve the root-level tenant ID (state-level) based on the facility's tenant ID + String rootTenantId = centralInstanceUtil.getStateLevelTenant(planFacilityRequest.getPlanFacility().getTenantId()); + + // Validate duplicate records for plan facility + validateDuplicateRecords(planFacilityRequest); + + // Validate PlanConfiguration Existence and fetch the plan configuration details using the PlanConfigurationId + List planConfigurations = fetchPlanConfigurationById(planFacilityRequest.getPlanFacility().getPlanConfigurationId(), rootTenantId); + + // Validate facility existence + validateFacilityExistence(planFacilityRequest); + + // Validate service boundaries and residing boundaries with campaign id + validateCampaignDetails(planConfigurations.get(0).getCampaignId(), rootTenantId, planFacilityRequest); + } + + /** + * Validates if plan facility linkage for the provided planConfiguration id and facility id already exists + * + * @param planFacilityRequest The plan facility linkage create request + */ + private void validateDuplicateRecords(@Valid PlanFacilityRequest planFacilityRequest) { + PlanFacility planFacility = planFacilityRequest.getPlanFacility(); + + PlanFacilitySearchCriteria searchCriteria = PlanFacilitySearchCriteria.builder().planConfigurationId(planFacility.getPlanConfigurationId()).facilityId(planFacility.getFacilityId()).build(); + + List planFacilityList = planFacilityRepository.search(searchCriteria); + + if (!CollectionUtils.isEmpty(planFacilityList)) { + throw new CustomException(PLAN_FACILITY_LINKAGE_ALREADY_EXISTS_CODE, PLAN_FACILITY_LINKAGE_ALREADY_EXISTS_MESSAGE); + } + } + + /** + * This method validates the Plan Facility Update request. + * It performs multiple validations such as plan facility existence + * and campaign-related validations. + * + * @param planFacilityRequest + */ + public void validatePlanFacilityUpdate(PlanFacilityRequest planFacilityRequest) { + String rootTenantId = centralInstanceUtil.getStateLevelTenant(planFacilityRequest.getPlanFacility().getTenantId()); + + //validate plan facility existence + validatePlanFacilityExistence(planFacilityRequest); + + List planConfigurations = fetchPlanConfigurationById(planFacilityRequest.getPlanFacility().getPlanConfigurationId(), rootTenantId); + + //validate service boundaries and residing boundaries with campaign id + validateCampaignDetails(planConfigurations.get(0).getCampaignId(), rootTenantId, planFacilityRequest); + } + + /** + * This method validates campaign id and service boundaries against project factory + * + * @param campaignId the campaign id corresponding to the plan config id provided in the request + * @param rootTenantId the tenant id provided in the request + * @param planFacilityRequest the plan facility request provided + */ + private void validateCampaignDetails(String campaignId, String rootTenantId, PlanFacilityRequest planFacilityRequest) { + PlanFacility planFacility = planFacilityRequest.getPlanFacility(); + Object mdmsData = mdmsUtil.fetchMdmsData(planFacilityRequest.getRequestInfo(), rootTenantId); + CampaignResponse campaignResponse = campaignUtil.fetchCampaignData(planFacilityRequest.getRequestInfo(), campaignId, rootTenantId); + + // Validate hierarchy type for campaign + Map hierarchyMap = commonUtil.getMicroplanHierarchy(mdmsData); + String lowestHierarchy = hierarchyMap.get(LOWEST_HIERARCHY_FIELD_FOR_MICROPLAN); + + // Collect all boundary code for the campaign + Set boundaryCodes = fetchBoundaryCodes(campaignResponse.getCampaignDetails().get(0), lowestHierarchy); + + // Validate residing boundaries + validateResidingBoundaries(boundaryCodes, planFacility); + + // Validate service boundaries + validateServiceBoundaries(boundaryCodes, planFacility); + + //Enrich jurisdiction mapping and boundary ancestral path + enrichment.enrichJurisdictionMapping(planFacilityRequest, campaignResponse.getCampaignDetails().get(0).getHierarchyType()); + } + + /** + * This method returns boundary code for the campaign + * + * @param campaignDetail + * @param lowestHierarchy + */ + private Set fetchBoundaryCodes(CampaignDetail campaignDetail, String lowestHierarchy) { + Set boundaryCodes = campaignDetail.getBoundaries().stream() + .filter(boundary -> lowestHierarchy.equals(boundary.getType().toLowerCase())) + .map(Boundary::getCode) + .collect(Collectors.toSet()); + + return boundaryCodes; + } + + /** + * This method validates if residing boundaries exist in campaign details + * + * @param boundaryCodes + * @param planFacility + */ + private void validateResidingBoundaries(Set boundaryCodes, PlanFacility planFacility) { + String residingBoundary = planFacility.getResidingBoundary(); + if (residingBoundary != null && !boundaryCodes.contains(residingBoundary)) { + throw new CustomException(INVALID_RESIDING_BOUNDARY_CODE, INVALID_RESIDING_BOUNDARY_MESSAGE); + } + } + + /** + * This method validates if service boundaries exist in campaign details + * + * @param boundaryCodes + * @param planFacility + */ + private void validateServiceBoundaries(Set boundaryCodes, PlanFacility planFacility) { + List serviceBoundaries = planFacility.getServiceBoundaries(); + + // Check for duplicate service boundaries + Set uniqueBoundaries = new HashSet<>(serviceBoundaries); + if (uniqueBoundaries.size() != serviceBoundaries.size()) { + throw new CustomException(INVALID_SERVICE_BOUNDARY_CODE, "Duplicate service boundaries are not allowed"); + } + + planFacility.getServiceBoundaries().forEach(serviceBoundary -> { + if (!boundaryCodes.contains(serviceBoundary)) { + throw new CustomException(INVALID_SERVICE_BOUNDARY_CODE, INVALID_SERVICE_BOUNDARY_MESSAGE); + } + }); + } + + /** + * This method validates if the hierarchy type provided in the request exists + * + * @param campaignResponse + * @param mdmsData + */ + private String validateHierarchyType(CampaignResponse campaignResponse, Object mdmsData) { + // Get the hierarchy type from the campaign response + String hierarchyType = campaignResponse.getCampaignDetails().get(0).getHierarchyType(); + + // Define the JSON path to fetch hierarchy configurations from MDMS data + final String jsonPathForHierarchy = JSON_ROOT_PATH + MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_MASTER_HIERARCHY_CONFIG + "[*]"; + + List> hierarchyConfigList = null; + try { + hierarchyConfigList = JsonPath.read(mdmsData, jsonPathForHierarchy); + } catch (Exception e) { + throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); + } + + // Iterate through the hierarchy configuration list + for (Map hierarchyConfig : hierarchyConfigList) { + if (hierarchyType.equals(hierarchyConfig.get(MDMS_MASTER_HIERARCHY))) { + // Return the lowest hierarchy value from the configuration + return (String) hierarchyConfig.get(LOWEST_HIERARCHY_FIELD_FOR_MICROPLAN); + } + } + // Throw exception if no matching hierarchy is found + throw new CustomException(HIERARCHY_NOT_FOUND_IN_MDMS_CODE, HIERARCHY_NOT_FOUND_IN_MDMS_MESSAGE); + } + + /** + * This method validates if the plan facility id provided in the update request exists + * + * @param planFacilityRequest + */ + private void validatePlanFacilityExistence(PlanFacilityRequest planFacilityRequest) { + List planFacilityListFromSearch = planFacilityRepository.search(PlanFacilitySearchCriteria.builder() + .ids(Collections.singleton(planFacilityRequest.getPlanFacility().getId())) + .build()); + + // If plan facility id provided is invalid, throw an exception + if (CollectionUtils.isEmpty(planFacilityListFromSearch)) { + throw new CustomException(INVALID_PLAN_FACILITY_ID_CODE, INVALID_PLAN_FACILITY_ID_MESSAGE); + } + + enrichInitialServiceBoundaries(planFacilityListFromSearch, planFacilityRequest); + } + + private void enrichInitialServiceBoundaries(List planFacilityListFromSearch, PlanFacilityRequest planFacilityRequest) { + + List initiallySetServiceBoundaries = planFacilityListFromSearch.get(0).getServiceBoundaries(); + planFacilityRequest.getPlanFacility().setInitiallySetServiceBoundaries(initiallySetServiceBoundaries); + } + + /** + * Searches the plan config based on the plan config id provided + * + * @param planConfigurationId + * @param tenantId + * @return + */ + public List fetchPlanConfigurationById(String planConfigurationId, String tenantId) { + List planConfigurations = planConfigurationRepository.search(PlanConfigurationSearchCriteria.builder() + .id(planConfigurationId) + .tenantId(tenantId) + .build()); + log.info("planConfigurations: " + planConfigurations); + + // Validate planConfiguration exists + if (CollectionUtils.isEmpty(planConfigurations)) { + throw new CustomException(INVALID_PLAN_CONFIG_ID_CODE, INVALID_PLAN_CONFIG_ID_MESSAGE); + } + + return planConfigurations; + } + + /** + * Validates if the facility with the provided ID exists in the system. + * + * @param planFacilityRequest + */ + private void validateFacilityExistence(PlanFacilityRequest planFacilityRequest) { + FacilityResponse facilityResponse = facilityUtil.fetchFacilityData(planFacilityRequest); + + // Use ObjectUtils and CollectionUtils to handle null or empty checks + if (ObjectUtils.isEmpty(facilityResponse) || CollectionUtils.isEmpty(facilityResponse.getFacilities())) { + throw new CustomException("FACILITY_NOT_FOUND", "Facility with ID " + planFacilityRequest.getPlanFacility().getFacilityId() + " not found in the system."); + } + + enrichFacilityDetails(facilityResponse.getFacilities().get(0), planFacilityRequest); + } + + private void enrichFacilityDetails(Facility facility, PlanFacilityRequest planFacilityRequest) { + String facilityName = facility.getName(); + planFacilityRequest.getPlanFacility().setFacilityName(facilityName); + BigDecimal initialServingPop = BigDecimal.ZERO; + + Map fieldsToBeAdded = new HashMap<>(); + fieldsToBeAdded.put("facilityUsage", facility.getUsage()); + fieldsToBeAdded.put("capacity", facility.getStorageCapacity()); + fieldsToBeAdded.put("facilityStatus", facility.getAddress().getType()); + fieldsToBeAdded.put("facilityType", facility.getUsage()); + fieldsToBeAdded.put("isPermanent", facility.isPermanent()); + fieldsToBeAdded.put("servingPopulation", initialServingPop); + + planFacilityRequest.getPlanFacility().setAdditionalDetails( + commonUtil.updateFieldInAdditionalDetails(planFacilityRequest.getPlanFacility().getAdditionalDetails(), fieldsToBeAdded)); + } + +} diff --git a/health-services/plan-service/src/main/java/digit/service/validator/WorkflowValidator.java b/health-services/plan-service/src/main/java/digit/service/validator/WorkflowValidator.java new file mode 100644 index 00000000000..321cdb36ecc --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/validator/WorkflowValidator.java @@ -0,0 +1,141 @@ +package digit.service.validator; + +import digit.service.PlanService; +import digit.util.CensusUtil; +import digit.web.models.*; +import digit.web.models.census.CensusResponse; +import digit.web.models.census.CensusSearchCriteria; +import digit.web.models.census.CensusSearchRequest; +import org.egov.common.contract.request.RequestInfo; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.util.Map; + +import static digit.config.ServiceConstants.*; +import static digit.config.ServiceConstants.CANNOT_APPROVE_ESTIMATIONS_MESSAGE; + +@Component +public class WorkflowValidator { + + private CensusUtil censusUtil; + + private PlanService planService; + + public WorkflowValidator(CensusUtil censusUtil, PlanService planService) { + this.censusUtil = censusUtil; + this.planService = planService; + } + + public void validateWorkflow(PlanConfigurationRequest planConfigurationRequest) { + if (ObjectUtils.isEmpty(planConfigurationRequest.getPlanConfiguration().getWorkflow())) + return; + + String workflowAction = planConfigurationRequest.getPlanConfiguration().getWorkflow().getAction(); + + if(workflowAction.equals(APPROVE_CENSUS_DATA_ACTION)) { + validateCensusData(planConfigurationRequest); + } else if(workflowAction.equals(FINALIZE_CATCHMENT_MAPPING_ACTION)) { + validateCatchmentMapping(planConfigurationRequest); + } else if(workflowAction.equals(APPROVE_ESTIMATIONS_ACTION)) { + validateResourceEstimations(planConfigurationRequest); + } + } + + /** + * Validates if all the census records are validated before approving census data for the given planConfigId. + * + * @param planConfigurationRequest request with plan config id. + */ + private void validateCensusData(PlanConfigurationRequest planConfigurationRequest) { + PlanConfiguration planConfiguration = planConfigurationRequest.getPlanConfiguration(); + + CensusSearchRequest censusSearchRequest = getCensusSearchRequest(planConfiguration.getTenantId(), planConfiguration.getId(), planConfigurationRequest.getRequestInfo()); + + // Fetches census records for given planConfigId + CensusResponse censusResponse = censusUtil.fetchCensusRecords(censusSearchRequest); + + Map statusCount = censusResponse.getStatusCount(); + Integer totalCount = censusResponse.getTotalCount(); + + // Throws exception if all census records are not validated + if (!statusCount.get(VALIDATED_STATUS).equals(totalCount)) { + throw new CustomException(CANNOT_APPROVE_CENSUS_DATA_CODE, CANNOT_APPROVE_CENSUS_DATA_MESSAGE); + } + } + + /** + * Validates if all boundaries have facility assigned before finalizing catchment mapping for a given planConfigID. + * + * @param planConfigurationRequest request with plan config id. + */ + private void validateCatchmentMapping(PlanConfigurationRequest planConfigurationRequest) { + PlanConfiguration planConfiguration = planConfigurationRequest.getPlanConfiguration(); + + CensusSearchRequest censusSearchRequest = getCensusSearchRequest(planConfiguration.getTenantId(), planConfiguration.getId(), planConfigurationRequest.getRequestInfo()); + + // Fetches all census records for given planConfigId + CensusResponse censusResponse = censusUtil.fetchCensusRecords(censusSearchRequest); + Integer totalCensusCount = censusResponse.getTotalCount(); + + censusSearchRequest.getCensusSearchCriteria().setFacilityAssigned(Boolean.TRUE); + + // Fetches all census records for given planConfigId where facility is assigned + CensusResponse censusWithFacilityAssigned = censusUtil.fetchCensusRecords(censusSearchRequest); + Integer totalCensusWithFacilityAssigned = censusWithFacilityAssigned.getTotalCount(); + + if (!totalCensusCount.equals(totalCensusWithFacilityAssigned)) { + throw new CustomException(CANNOT_FINALIZE_CATCHMENT_MAPPING_CODE, CANNOT_FINALIZE_CATCHMENT_MAPPING_MESSAGE); + } + } + + /** + * Validates if all the plan estimations are validated before approving estimations for the given planConfigId. + * + * @param planConfigurationRequest request with plan config id. + */ + private void validateResourceEstimations(PlanConfigurationRequest planConfigurationRequest) { + PlanConfiguration planConfiguration = planConfigurationRequest.getPlanConfiguration(); + + PlanSearchRequest searchRequest = getPlanSearchRequest(planConfiguration.getTenantId(), planConfiguration.getId(), planConfigurationRequest.getRequestInfo()); + + // Fetches plans for given planConfigId + PlanResponse planResponse = planService.searchPlan(searchRequest); + + Map statusCount = planResponse.getStatusCount(); + Integer totalCount = planResponse.getTotalCount(); + + // Throws exception if all plans are not validated + if (!statusCount.get(VALIDATED_STATUS).equals(totalCount)) { + throw new CustomException(CANNOT_APPROVE_ESTIMATIONS_CODE, CANNOT_APPROVE_ESTIMATIONS_MESSAGE); + } + } + + // Prepares Census search request for given planConfigId + private CensusSearchRequest getCensusSearchRequest(String tenantId, String planConfigId, RequestInfo requestInfo) { + CensusSearchCriteria searchCriteria = CensusSearchCriteria.builder() + .tenantId(tenantId) + .source(planConfigId) + .build(); + + return CensusSearchRequest.builder() + .requestInfo(requestInfo) + .censusSearchCriteria(searchCriteria) + .build(); + } + + // Prepares Plan search request for given planConfigId + private PlanSearchRequest getPlanSearchRequest(String tenantId, String planConfigId, RequestInfo requestInfo) { + PlanSearchCriteria searchCriteria = PlanSearchCriteria.builder() + .tenantId(tenantId) + .planConfigurationId(planConfigId) + .build(); + + return PlanSearchRequest.builder() + .requestInfo(requestInfo) + .planSearchCriteria(searchCriteria) + .build(); + } + +} diff --git a/health-services/plan-service/src/main/java/digit/service/workflow/WorkflowService.java b/health-services/plan-service/src/main/java/digit/service/workflow/WorkflowService.java new file mode 100644 index 00000000000..24932950df8 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/workflow/WorkflowService.java @@ -0,0 +1,432 @@ +package digit.service.workflow; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.config.Configuration; +import digit.repository.ServiceRequestRepository; +import digit.service.PlanEmployeeService; +import digit.service.validator.PlanConfigurationValidator; +import digit.util.CommonUtil; +import digit.web.models.*; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.models.Workflow; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.request.User; +import org.egov.common.contract.workflow.*; +import org.egov.common.utils.AuditDetailsEnrichmentUtil; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.web.client.RestTemplate; + +import java.util.*; +import java.util.stream.Collectors; + +import static digit.config.ServiceConstants.*; +import static digit.config.ServiceConstants.NO_BUSINESS_SERVICE_DATA_FOUND_MESSAGE; + +@Service +@Slf4j +public class WorkflowService { + + private ServiceRequestRepository serviceRequestRepository; + + private Configuration config; + + private ObjectMapper mapper; + + private CommonUtil commonUtil; + + private PlanEmployeeService planEmployeeService; + + private PlanConfigurationValidator planConfigurationValidator; + + private RestTemplate restTemplate; + + public WorkflowService(ServiceRequestRepository serviceRequestRepository, Configuration config, ObjectMapper mapper, CommonUtil commonUtil, PlanEmployeeService planEmployeeService, PlanConfigurationValidator planConfigurationValidator, RestTemplate restTemplate) { + this.serviceRequestRepository = serviceRequestRepository; + this.config = config; + this.mapper = mapper; + this.commonUtil = commonUtil; + this.planEmployeeService = planEmployeeService; + this.planConfigurationValidator = planConfigurationValidator; + this.restTemplate = restTemplate; + } + + /** + * Integrates with the workflow for the given plan configuration request. + * If the action is null, it does not proceed with integration. + * + * @param planConfigurationRequest The request containing the plan configuration to integrate with the workflow. + */ + public void invokeWorkflowForStatusUpdate(PlanConfigurationRequest planConfigurationRequest) { + if (ObjectUtils.isEmpty(planConfigurationRequest.getPlanConfiguration().getWorkflow())) + return; + + ProcessInstanceRequest processInstanceRequest = createWorkflowRequest(planConfigurationRequest); + ProcessInstanceResponse processInstanceResponse = callWorkflowTransition(processInstanceRequest); + + // Setting the status back to the plan configuration object from workflow response + planConfigurationRequest.getPlanConfiguration().setStatus(processInstanceResponse.getProcessInstances().get(0).getState().getState()); + } + + /** + * Integrates with the workflow for the given plan request. + * If the action is null, it does not proceed with integration. + * + * @param planRequest The request containing the plan estimate to integrate with the workflow. + */ + public void invokeWorkflowForStatusUpdate(PlanRequest planRequest) { + if (ObjectUtils.isEmpty(planRequest.getPlan().getWorkflow())) + return; + + ProcessInstanceRequest processInstanceRequest = createWorkflowRequest(planRequest); + ProcessInstanceResponse processInstanceResponse = callWorkflowTransition(processInstanceRequest); + + // Setting the status back to the plan configuration object from workflow response + planRequest.getPlan().setStatus(processInstanceResponse.getProcessInstances().get(0).getState().getState()); + + // Enrich audit details after auto assignment is complete + planRequest.getPlan().setAuditDetails(AuditDetailsEnrichmentUtil + .prepareAuditDetails( planRequest.getPlan().getAuditDetails(), planRequest.getRequestInfo(), Boolean.FALSE)); + + } + + /** + * Calls the workflow transition service and retrieves the process instance response. + * + * @param processInstanceRequest The request containing process instance details for the workflow transition. + * @return The response containing details of the process instances after the transition. + * @throws CustomException if there is an error during the workflow integration. + */ + public ProcessInstanceResponse callWorkflowTransition(ProcessInstanceRequest processInstanceRequest) { + ProcessInstanceResponse processInstanceResponse; + try { + Object response = serviceRequestRepository.fetchResult(getWorkflowTransitionUri(), processInstanceRequest); + processInstanceResponse = mapper.convertValue(response, ProcessInstanceResponse.class); + } catch (Exception e) { + throw new CustomException(WORKFLOW_INTEGRATION_ERROR_CODE, WORKFLOW_INTEGRATION_ERROR_MESSAGE + e.getMessage()); + } + + return processInstanceResponse; + } + + /** + * Creates a workflow request from the given plan configuration request. + * + * @param planConfigurationRequest The request containing the plan configuration to create a workflow request. + * @return The constructed process instance request for the workflow. + */ + public ProcessInstanceRequest createWorkflowRequest(PlanConfigurationRequest planConfigurationRequest) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + ProcessInstance processInstance = ProcessInstance.builder() + .businessId(planConfig.getId()) + .tenantId(planConfig.getTenantId()) + .businessService(PLAN_CONFIGURATION_BUSINESS_SERVICE) + .moduleName(MODULE_NAME_VALUE) + .action(planConfig.getWorkflow().getAction()) + .comment(planConfig.getWorkflow().getComments()) + .documents(planConfig.getWorkflow().getDocuments()) + .build(); + + enrichAssignesInProcessInstance(processInstance, planConfig.getWorkflow()); + + return ProcessInstanceRequest.builder() + .requestInfo(planConfigurationRequest.getRequestInfo()) + .processInstances(Collections.singletonList(processInstance)) + .build(); + } + + /** + * Creates a workflow request from the given plan configuration request. + * + * @param planRequest The request containing the plan to create a workflow request. + * @return The constructed process instance request for the workflow. + */ + public ProcessInstanceRequest createWorkflowRequest(PlanRequest planRequest) { + Plan plan = planRequest.getPlan(); + ProcessInstance processInstance = ProcessInstance.builder() + .businessId(plan.getId()) + .tenantId(plan.getTenantId()) + .businessService(PLAN_ESTIMATION_BUSINESS_SERVICE) + .moduleName(MODULE_NAME_VALUE) + .action(plan.getWorkflow().getAction()) + .comment(plan.getWorkflow().getComments()) + .documents(plan.getWorkflow().getDocuments()) + .build(); + + List assignee = getAssigneeForAutoAssignment(plan, planRequest.getRequestInfo()); + + // Set assignees for send back actions + if (config.getWfSendBackActions().contains(plan.getWorkflow().getAction())) { + assignee = Collections.singletonList(plan.getAuditDetails().getLastModifiedBy()); + } + + // Set Assignee + if(!ObjectUtils.isEmpty(assignee)) + plan.getWorkflow().setAssignes(assignee); + + plan.setAssignee(assignee); + + enrichAssignesInProcessInstance(processInstance, plan.getWorkflow()); + + log.info("Process Instance assignes - " + processInstance.getAssignes()); + return ProcessInstanceRequest.builder() + .requestInfo(planRequest.getRequestInfo()) + .processInstances(Collections.singletonList(processInstance)) + .build(); + } + + /** + * Enriches the process instance with assignees from the given workflow. + * + * @param processInstance The process instance to enrich with assignees. + * @param workflow The workflow containing assignees to be added to the process instance. + */ + public void enrichAssignesInProcessInstance(ProcessInstance processInstance, Workflow workflow) { + List userList = CollectionUtils.isEmpty(workflow.getAssignes()) + ? new LinkedList<>() + : workflow.getAssignes().stream() + .map(assignee -> User.builder().uuid(assignee).build()) + .toList(); + + processInstance.setAssignes(userList); + } + + /** + * Constructs the URI for the workflow service transition API. + * + * @return The StringBuilder containing the constructed workflow transition URI. + */ + private StringBuilder getWorkflowTransitionUri() { + return new StringBuilder().append(config.getWfHost()).append(config.getWfTransitionPath()); + } + + /** + * Automatically assigns a list of assignee based on the workflow action and jurisdiction hierarchy. + * Retrieves jurisdiction boundaries from the plan request and searches for matching employee assignments. + * + * For INITIATE actions, assigns the employee from the lowest boundary. + * For INTERMEDIATE actions (non-ROOT_APPROVER), assigns an employee from a higher-level boundary. + * For SEND_BACK actions, assigns the last modified user. + * + * The assignee is set in both the workflow and the plan request. + * + * @param requestInfo auth details for making internal calls + * @param plan the plan object containing workflow and jurisdiction details + */ + private List getAssigneeForAutoAssignment(Plan plan, RequestInfo requestInfo) { + String[] allheirarchysBoundaryCodes = plan.getBoundaryAncestralPath().split(PIPE_REGEX); + String[] heirarchysBoundaryCodes = Arrays.copyOf(allheirarchysBoundaryCodes, allheirarchysBoundaryCodes.length - 1); + + PlanEmployeeAssignmentSearchCriteria planEmployeeAssignmentSearchCriteria = + PlanEmployeeAssignmentSearchCriteria.builder() + .tenantId(plan.getTenantId()) + .jurisdiction(Arrays.stream(heirarchysBoundaryCodes).toList()) + .planConfigurationId(plan.getPlanConfigurationId()) + .role(config.getPlanEstimationApproverRoles()) + .build(); + + //search for plan-employee assignments for the ancestral heirarchy codes. + PlanEmployeeAssignmentResponse planEmployeeAssignmentResponse = planEmployeeService.search(PlanEmployeeAssignmentSearchRequest.builder() + .planEmployeeAssignmentSearchCriteria(planEmployeeAssignmentSearchCriteria) + .requestInfo(requestInfo).build()); + + // Create a map of jurisdiction to list of employeeIds + Map> jurisdictionToEmployeeMap = planEmployeeAssignmentResponse.getPlanEmployeeAssignment().stream() + .filter(assignment -> assignment.getJurisdiction() != null && !assignment.getJurisdiction().isEmpty()) + .flatMap(assignment -> { + String employeeId = assignment.getEmployeeId(); + return assignment.getJurisdiction().stream() + .filter(jurisdiction -> Arrays.asList(heirarchysBoundaryCodes).contains(jurisdiction)) + .map(jurisdiction -> new AbstractMap.SimpleEntry<>(jurisdiction, employeeId)); + }) + .collect(Collectors.groupingBy( + Map.Entry::getKey, // jurisdiction as the key + LinkedHashMap::new, // Preserve insertion order + Collectors.mapping( + Map.Entry::getValue, // employee IDs as values + Collectors.toList() // Collect employee IDs into a List + ) + )); + + List assignee = null; //assignee will remain null in case terminate actions are being taken + + String action = plan.getWorkflow().getAction(); + if (config.getWfInitiateActions().contains(action)) { + for (int i = heirarchysBoundaryCodes.length - 1; i >= 0; i--) { + assignee = jurisdictionToEmployeeMap.get(heirarchysBoundaryCodes[i]); + if (assignee != null) + break; // Stop iterating once an assignee is found + } + } else if (config.getWfIntermediateActions().contains(action)) { + assignee = assignToHigherBoundaryLevel(heirarchysBoundaryCodes, plan, jurisdictionToEmployeeMap); + } + + return assignee; + } + + /** + * Assigns a list of employees from a higher-level jurisdiction in the hierarchy. + * Iterates through boundary codes, checking if they match the assignee's jurisdiction. + * If a higher-level boundary has an assigned employee, returns that employee's ID. + * + * @param heirarchysBoundaryCodes boundary codes representing the hierarchy + * @param plan the object with plan and jurisdiction details + * @param jurisdictionToEmployeeMap map of jurisdiction codes to employee IDs + * @return the employee ID from the higher boundary, or null if + */ + public List assignToHigherBoundaryLevel(String[] heirarchysBoundaryCodes, Plan plan, Map> jurisdictionToEmployeeMap) { + for (int i = heirarchysBoundaryCodes.length - 1; i >= 0; i--) { + String boundaryCode = heirarchysBoundaryCodes[i]; + + // Check if this boundary code is present in assigneeJurisdiction + if (plan.getAssigneeJurisdiction().contains(boundaryCode)) { + + for (int j = i - 1; j >= 0; j--) { + // Check the next higher level in the hierarchy (one index above the match) + String higherBoundaryCode = heirarchysBoundaryCodes[j]; + + // Fetch the employeeId from the map for the higher boundary code + List employeeId = jurisdictionToEmployeeMap.get(higherBoundaryCode); + + // If an employee is found, set them as the assignee and break the loop + if (employeeId != null) { + return employeeId; + } + } + } + } + return null; + } + + public void invokeWorkflowForStatusUpdate(BulkPlanRequest bulkPlanRequest) { + ProcessInstanceRequest processInstanceRequest = createWorkflowRequest(bulkPlanRequest); + ProcessInstanceResponse processInstanceResponse = callWorkflowTransition(processInstanceRequest); + + enrichPlansPostTransition(processInstanceResponse, bulkPlanRequest); + } + + private void enrichPlansPostTransition(ProcessInstanceResponse processInstanceResponse, BulkPlanRequest bulkPlanRequest) { + // Update status and audit information post transition + bulkPlanRequest.getPlans().forEach(plan -> { + // Update status of plan + plan.setStatus(processInstanceResponse.getProcessInstances().get(0).getState().getState()); + + // Update audit information of plan + plan.setAuditDetails(AuditDetailsEnrichmentUtil + .prepareAuditDetails(plan.getAuditDetails(), bulkPlanRequest.getRequestInfo(), Boolean.FALSE)); + }); + } + + private ProcessInstanceRequest createWorkflowRequest(BulkPlanRequest bulkPlanRequest) { + List processInstanceList = new ArrayList<>(); + + // Perform auto assignment + List assignee = getAssigneeForAutoAssignment(bulkPlanRequest.getPlans().get(0), + bulkPlanRequest.getRequestInfo()); + + for(Plan plan: bulkPlanRequest.getPlans()) { + + // Setting assignee for send back actions + if (config.getWfSendBackActions().contains(plan.getWorkflow().getAction())) { + assignee = Collections.singletonList(plan.getAuditDetails().getLastModifiedBy()); + } + + // Set assignee + if(!ObjectUtils.isEmpty(assignee)) + plan.getWorkflow().setAssignes(assignee); + + plan.setAssignee(assignee); + + // Create process instance object from plan + ProcessInstance processInstance = ProcessInstance.builder() + .businessId(plan.getId()) + .tenantId(plan.getTenantId()) + .businessService(PLAN_ESTIMATION_BUSINESS_SERVICE) + .moduleName(MODULE_NAME_VALUE) + .action(plan.getWorkflow().getAction()) + .comment(plan.getWorkflow().getComments()) + .documents(plan.getWorkflow().getDocuments()) + .build(); + + // Enrich user list for process instance + enrichAssignesInProcessInstance(processInstance, plan.getWorkflow()); + + // Add entry for bulk transition + processInstanceList.add(processInstance); + } + + return ProcessInstanceRequest.builder() + .requestInfo(bulkPlanRequest.getRequestInfo()) + .processInstances(processInstanceList) + .build(); + } + + /** + * Creates a list of all the workflow states for the provided business service. + * @param requestInfo + * @param businessService + * @param tenantId + * @return + */ + public List getStatusFromBusinessService(RequestInfo requestInfo, String businessService, String tenantId) { + BusinessService businessServices = fetchBusinessService(requestInfo, businessService, tenantId); + + return businessServices.getStates().stream() + .map(State::getState) + .filter(state -> !ObjectUtils.isEmpty(state)) + .toList(); + } + + /** + * This method fetches business service details for the given tenant id and business service. + * + * @param requestInfo the request info from request. + * @param businessService businessService whose details are to be searched. + * @param tenantId tenantId from request. + * @return returns the business service response for the given tenant id and business service. + */ + public BusinessService fetchBusinessService(RequestInfo requestInfo, String businessService, String tenantId) { + + // Get business service uri + Map uriParameters = new HashMap<>(); + String uri = getBusinessServiceUri(businessService, tenantId, uriParameters); + + // Create request body + RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(requestInfo).build(); + BusinessServiceResponse businessServiceResponse = new BusinessServiceResponse(); + + try { + businessServiceResponse = restTemplate.postForObject(uri, requestInfoWrapper, BusinessServiceResponse.class, uriParameters); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_BUSINESS_SERVICE_DETAILS, e); + } + + if (CollectionUtils.isEmpty(businessServiceResponse.getBusinessServices())) { + throw new CustomException(NO_BUSINESS_SERVICE_DATA_FOUND_CODE, NO_BUSINESS_SERVICE_DATA_FOUND_MESSAGE); + } + + return businessServiceResponse.getBusinessServices().get(0); + } + + /** + * This method creates business service uri with query parameters + * + * @param businessService businessService whose details are to be searched. + * @param tenantId tenant id from the request. + * @param uriParameters map that stores values corresponding to the placeholder in uri + * @return + */ + private String getBusinessServiceUri(String businessService, String tenantId, Map uriParameters) { + + StringBuilder uri = new StringBuilder(); + uri.append(config.getWfHost()).append(config.getBusinessServiceSearchEndpoint()).append(URI_BUSINESS_SERVICE_QUERY_TEMPLATE); + + uriParameters.put(URI_TENANT_ID_PARAM, tenantId); + uriParameters.put(URI_BUSINESS_SERVICE_PARAM, businessService); + + return uri.toString(); + } + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/util/BoundaryUtil.java b/health-services/plan-service/src/main/java/digit/util/BoundaryUtil.java new file mode 100644 index 00000000000..ec43e0f0447 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/util/BoundaryUtil.java @@ -0,0 +1,111 @@ +package digit.util; + +import digit.config.Configuration; +import digit.web.models.RequestInfoWrapper; +import digit.web.models.boundary.BoundarySearchResponse; +import digit.web.models.boundary.BoundaryTypeHierarchyResponse; +import digit.web.models.boundary.BoundaryTypeHierarchySearchCriteria; +import digit.web.models.boundary.BoundaryTypeHierarchySearchRequest; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.util.HashMap; +import java.util.Map; +import static digit.config.ServiceConstants.ERROR_WHILE_FETCHING_BOUNDARY_DETAILS; +import static digit.config.ServiceConstants.ERROR_WHILE_FETCHING_BOUNDARY_HIERARCHY_DETAILS; + + +@Slf4j +@Component +public class BoundaryUtil { + + private RestTemplate restTemplate; + + private Configuration configs; + + public BoundaryUtil(RestTemplate restTemplate, Configuration configs) { + this.restTemplate = restTemplate; + this.configs = configs; + } + + /** + * This method fetches boundary relationships from Boundary service for the provided boundaryCode and hierarchyType. + * + * @param requestInfo request info from the request. + * @param boundaryCode boundary code from the request. + * @param tenantId tenant id from the request. + * @param hierarchyType hierarchy type from the request. + * @param includeParents is true if you want to include parent boundary. + * @param includeChildren is true if you want to include child boundary. + * @return returns the response from boundary service + */ + public BoundarySearchResponse fetchBoundaryData(RequestInfo requestInfo, String boundaryCode, String tenantId, String hierarchyType, Boolean includeParents, Boolean includeChildren) { + + // Create Boundary Relationship search uri + Map uriParameters = new HashMap<>(); + StringBuilder uri = getBoundaryRelationshipSearchUri(uriParameters, boundaryCode, tenantId, hierarchyType, includeParents, includeChildren); + + // Create request body + RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(requestInfo).build(); + BoundarySearchResponse boundarySearchResponse = new BoundarySearchResponse(); + + try { + boundarySearchResponse = restTemplate.postForObject(uri.toString(), requestInfoWrapper, BoundarySearchResponse.class, uriParameters); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_BOUNDARY_DETAILS, e); + } + + return boundarySearchResponse; + } + + /** + * This method creates Boundary service uri with query parameters + * + * @param uriParameters map that stores values corresponding to the placeholder in uri + * @param boundaryCode boundary code from the request. + * @param tenantId tenant id from the request. + * @param hierarchyType hierarchy type from the request. + * @param includeParents is true if you want to include parent boundary. + * @param includeChildren is true if you want to include child boundary. + * @return a complete boundary service uri + */ + private StringBuilder getBoundaryRelationshipSearchUri(Map uriParameters, String boundaryCode, String tenantId, String hierarchyType, Boolean includeParents, Boolean includeChildren) { + StringBuilder uri = new StringBuilder(); + uri.append(configs.getBoundaryServiceHost()).append(configs.getBoundaryRelationshipSearchEndpoint()).append("?codes={boundaryCode}&includeParents={includeParents}&includeChildren={includeChildren}&tenantId={tenantId}&hierarchyType={hierarchyType}"); + + uriParameters.put("boundaryCode", boundaryCode); + uriParameters.put("tenantId", tenantId); + uriParameters.put("includeParents", includeParents.toString()); + uriParameters.put("includeChildren", includeChildren.toString()); + uriParameters.put("hierarchyType", hierarchyType); + + return uri; + } + + public BoundaryTypeHierarchyResponse fetchBoundaryHierarchy(RequestInfo requestInfo, String tenantId, String hierarchyType) { + + // Create Boundary hierarchy search uri + String uri = getBoundaryHierarchySearchUri(); + + // Create request body + BoundaryTypeHierarchySearchCriteria searchCriteria = BoundaryTypeHierarchySearchCriteria.builder().tenantId(tenantId).hierarchyType(hierarchyType).build(); + BoundaryTypeHierarchySearchRequest searchRequest = BoundaryTypeHierarchySearchRequest.builder().requestInfo(requestInfo).boundaryTypeHierarchySearchCriteria(searchCriteria).build(); + BoundaryTypeHierarchyResponse searchResponse = new BoundaryTypeHierarchyResponse(); + + try { + searchResponse = restTemplate.postForObject(uri, searchRequest, BoundaryTypeHierarchyResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_BOUNDARY_HIERARCHY_DETAILS, e); + } + + return searchResponse; + } + + private String getBoundaryHierarchySearchUri() { + StringBuilder uri = new StringBuilder(); + uri.append(configs.getBoundaryServiceHost()).append(configs.getBoundaryHierarchySearchEndpoint()); + return uri.toString(); + } +} diff --git a/health-services/plan-service/src/main/java/digit/util/CampaignUtil.java b/health-services/plan-service/src/main/java/digit/util/CampaignUtil.java new file mode 100644 index 00000000000..5f1632e6366 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/util/CampaignUtil.java @@ -0,0 +1,91 @@ +package digit.util; + +import digit.config.Configuration; + +import digit.web.models.projectFactory.*; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.web.client.RestTemplate; + +import java.util.Collections; + +import static digit.config.ServiceConstants.*; + +@Slf4j +@Component +public class CampaignUtil { + + private RestTemplate restTemplate; + + private Configuration configs; + + public CampaignUtil(RestTemplate restTemplate, Configuration configs) { + this.restTemplate = restTemplate; + this.configs = configs; + } + + /** + * This method fetches data from project factory for provided campaignId and service boundaries + * + * @param requestInfo request info from the request + * @param campaignId campaign id provided in the request + * @param tenantId tenant id from the request + */ + public CampaignResponse fetchCampaignData(RequestInfo requestInfo, String campaignId, String tenantId) { + + // Build the URI for calling the Project Factory service + StringBuilder uri = buildCampaignSearchUri(); + + // Prepare the search request object with required campaign ID, tenant ID, and request information + CampaignSearchReq campaignSearchReq = getCampaignSearchRequest(requestInfo, campaignId, tenantId); + CampaignResponse campaignResponse = null; + + try { + campaignResponse = restTemplate.postForObject(uri.toString(), campaignSearchReq, CampaignResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_PROJECT_FACTORY, e); + } + + // Validate that the response contains campaign details, otherwise throw an exception + if (CollectionUtils.isEmpty(campaignResponse.getCampaignDetails())) { + throw new CustomException(NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_CODE, NO_CAMPAIGN_DETAILS_FOUND_FOR_GIVEN_CAMPAIGN_ID_MESSAGE); + } + + return campaignResponse; + } + + /** + * This method create the uri for project factory to fetch campaign data. + * + * @return The complete URI. + */ + private StringBuilder buildCampaignSearchUri() { + return new StringBuilder().append(configs.getProjectFactoryHost()).append(configs.getProjectFactorySearchEndPoint()); + } + + /** + * Creates the request object for fetching campaign data. + * + * @param requestInfo Information about the request such as user details and correlation ID. + * @param campaignId The ID of the campaign to be searched. + * @param tenantId The tenant identifier (for multi-tenant support). + * @return The request object containing the search criteria and request info. + */ + private CampaignSearchReq getCampaignSearchRequest(RequestInfo requestInfo, String campaignId, String tenantId) { + Pagination pagination = Pagination.builder() + .limit(configs.getDefaultLimit()) + .offset(configs.getDefaultOffset()) + .build(); + + CampaignSearchCriteria searchCriteria = CampaignSearchCriteria.builder() + .ids(Collections.singletonList(campaignId)) + .tenantId(tenantId) + .pagination(pagination) + .build(); + + return CampaignSearchReq.builder().requestInfo(requestInfo).campaignSearchCriteria(searchCriteria).build(); + } +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/util/CensusUtil.java b/health-services/plan-service/src/main/java/digit/util/CensusUtil.java new file mode 100644 index 00000000000..fa45518c44a --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/util/CensusUtil.java @@ -0,0 +1,60 @@ +package digit.util; + +import digit.config.Configuration; +import digit.web.models.census.CensusResponse; +import digit.web.models.census.CensusSearchRequest; +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.web.client.RestTemplate; + +import static digit.config.ServiceConstants.*; + +@Slf4j +@Component +public class CensusUtil { + + private RestTemplate restTemplate; + + private Configuration config; + + public CensusUtil(RestTemplate restTemplate, Configuration config) { + this.restTemplate = restTemplate; + this.config = config; + } + + /** + * This method fetches data from Census based on the given census search request. + * + * @param searchRequest The census search request containing the search criteria. + * @return returns the census response. + */ + public CensusResponse fetchCensusRecords(CensusSearchRequest searchRequest) { + + // Get census search uri + String uri = getCensusUri().toString(); + + CensusResponse censusResponse = null; + try { + censusResponse = restTemplate.postForObject(uri, searchRequest, CensusResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_CENSUS, e); + } + + if (CollectionUtils.isEmpty(censusResponse.getCensus())) { + throw new CustomException(NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_CODE, NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_MESSAGE); + } + + return censusResponse; + } + + /** + * Builds the census search uri. + * + * @return returns the complete uri for census search. + */ + private StringBuilder getCensusUri() { + return new StringBuilder().append(config.getCensusHost()).append(config.getCensusSearchEndPoint()); + } +} diff --git a/health-services/plan-service/src/main/java/digit/util/CommonUtil.java b/health-services/plan-service/src/main/java/digit/util/CommonUtil.java new file mode 100644 index 00000000000..6635294fd87 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/util/CommonUtil.java @@ -0,0 +1,275 @@ +package digit.util; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.NullNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.jayway.jsonpath.JsonPath; +import digit.repository.PlanConfigurationRepository; +import digit.web.models.Operation; +import digit.web.models.PlanConfiguration; +import digit.web.models.PlanConfigurationSearchCriteria; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.text.StringEscapeUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.math.BigDecimal; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static digit.config.ServiceConstants.*; + +@Component +@Slf4j +public class CommonUtil { + + private PlanConfigurationRepository planConfigurationRepository; + + private ObjectMapper objectMapper; + + public CommonUtil(PlanConfigurationRepository planConfigurationRepository, ObjectMapper objectMapper) { + this.planConfigurationRepository = planConfigurationRepository; + this.objectMapper = objectMapper; + } + + /** + * Validates the given input string against the provided regex pattern. + * + * @param patternString the regex pattern to validate against + * @param inputString the input string to be validated + * @return true if the input string matches the regex pattern, false otherwise + */ + public Boolean validateStringAgainstRegex(String patternString, String inputString) { + Pattern pattern = Pattern.compile(patternString); + Matcher matcher = pattern.matcher(inputString); + return matcher.matches(); + } + + + /** + * Extracts provided field from the additional details object + * + * @param additionalDetails the additionalDetails object from PlanConfigurationRequest + * @param fieldToExtract the name of the field to be extracted from the additional details + * @return the value of the specified field as a string + * @throws CustomException if the field does not exist + */ + public Object extractFieldsFromJsonObject(Object additionalDetails, String fieldToExtract) { + try { + String jsonString = objectMapper.writeValueAsString(additionalDetails); + JsonNode rootNode = objectMapper.readTree(jsonString); + + JsonNode node = rootNode.get(fieldToExtract); + if (node != null && !node.isNull()) { + + // Check for different types of JSON nodes + if (node.isDouble() || node.isFloat()) { + return BigDecimal.valueOf(node.asDouble()); // Convert Double to BigDecimal + } else if (node.isLong() || node.isInt()) { + return BigDecimal.valueOf(node.asLong()); // Convert Long to BigDecimal + } else if (node.isBoolean()) { + return node.asBoolean(); + } else if (node.isTextual()) { + return node.asText(); + } + } + return null; + } catch (Exception e) { + log.error(e.getMessage() + fieldToExtract); + throw new CustomException(PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_CODE, PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_MESSAGE + fieldToExtract); + } + } + + /** + * Extracts provided field from the additional details object + * + * @param additionalDetails the additionalDetails object from PlanConfigurationRequest + * @param fieldToExtract the name of the field to be extracted from the additional details + * @return the value of the specified field as a list of string + * @throws CustomException if the field does not exist + */ + public List extractFieldsFromJsonObject(Object additionalDetails, String fieldToExtract, Class valueType) { + try { + String jsonString = objectMapper.writeValueAsString(additionalDetails); + JsonNode rootNode = objectMapper.readTree(jsonString); + + JsonNode node = rootNode.get(fieldToExtract); + List list = new ArrayList<>(); + if (node != null && node.isArray()) { + for (JsonNode idNode : node) { + list.add(idNode.asText()); + } + } + return list; + } catch (Exception e) { + log.error(e.getMessage() + fieldToExtract); + throw new CustomException(PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_CODE, PROVIDED_KEY_IS_NOT_PRESENT_IN_JSON_OBJECT_MESSAGE + fieldToExtract); + } + } + + /** + * Constructs a JSONPath expression used to filter assumptions based on the given parameters - + * campaign type, distribution process, registration process, resource distribution strategy, + * and whether registration and distribution are together match the provided values. + * + * @param campaignType The type of campaign to filter by (e.g., "Health", "Education"). + * @param distributionProcess The process of distribution to filter by (e.g., "Central", "Decentralized"). + * @param registrationProcess The registration process to filter by (e.g., "Online", "In-Person"). + * @param resourceDistributionStrategyCode The strategy code for resource distribution to filter by (e.g., "Strategy1"). + * @param isRegistrationAndDistributionTogether Whether registration and distribution are combined, to filter by ("true"/"false"). + * @return A JSONPath expression string that filters assumptions based on the given criteria. + */ + public String createJsonPathForAssumption( + String campaignType, + String distributionProcess, + String registrationProcess, + String resourceDistributionStrategyCode, + String isRegistrationAndDistributionTogether + ) { + + StringBuilder jsonPathFilters = new StringBuilder(JSONPATH_FILTER_PREFIX); + jsonPathFilters.append(JSON_PATH_FILTER_CAMPAIGN_TYPE).append(EQUALS).append(SINGLE_QUOTE).append(StringEscapeUtils.escapeJson(campaignType)).append(SINGLE_QUOTE) + .append(AND).append(JSON_PATH_FILTER_DISTRIBUTION_PROCESS).append(EQUALS).append(SINGLE_QUOTE).append(StringEscapeUtils.escapeJson(distributionProcess)).append(SINGLE_QUOTE) + .append(AND).append(JSON_PATH_FILTER_REGISTRATION_PROCESS).append(EQUALS).append(SINGLE_QUOTE).append(StringEscapeUtils.escapeJson(registrationProcess)).append(SINGLE_QUOTE) + .append(AND).append(JSON_PATH_FILTER_RESOURCE_DISTRIBUTION_STRATEGY_CODE).append(EQUALS).append(SINGLE_QUOTE).append(StringEscapeUtils.escapeJson(resourceDistributionStrategyCode)).append(SINGLE_QUOTE) + .append(AND).append(JSON_PATH_FILTER_IS_REGISTRATION_AND_DISTRIBUTION_TOGETHER).append(EQUALS).append(SINGLE_QUOTE).append(StringEscapeUtils.escapeJson(isRegistrationAndDistributionTogether)).append(SINGLE_QUOTE) + .append(JSONPATH_FILTER_SUFFIX); + + return JSON_ROOT_PATH + MDMS_PLAN_MODULE_NAME + DOT_SEPARATOR + MDMS_MASTER_ASSUMPTION + jsonPathFilters + FILTER_ALL_ASSUMPTIONS; + } + + + /** + * Searches the plan config based on the plan config id provided + * + * @param planConfigId the plan config id to validate + * @param tenantId the tenant id of the plan config + * @return list of planConfiguration for the provided plan config id + */ + public List searchPlanConfigId(String planConfigId, String tenantId) { + List planConfigurations = planConfigurationRepository.search(PlanConfigurationSearchCriteria.builder() + .id(planConfigId) + .tenantId(tenantId) + .build()); + + return planConfigurations; + } + + /** + * This method returns the planConfigName for the provided planConfig id + * + * @param tenantId + * @param planConfigId + */ + public String getPlanConfigName(String tenantId, String planConfigId) { + + List planConfigsFromSearch = searchPlanConfigId(planConfigId, tenantId); + return planConfigsFromSearch.get(0).getName(); + } + + /** + * Validates the user information within the provided PlanConfigurationRequest. + * + * @param requestInfo the request info containing the user information to be validated + * @throws CustomException if the user information is missing in the request + */ + public void validateUserInfo(RequestInfo requestInfo) + { + if (ObjectUtils.isEmpty(requestInfo.getUserInfo())) { + log.error(USERINFO_MISSING_MESSAGE); + throw new CustomException(USERINFO_MISSING_CODE, USERINFO_MISSING_MESSAGE); + } + } + + /** + * This is a helper method to get the lowest and highest hierarchy for microplan from MDMS + * + * @param mdmsData the mdms data + * @return returns the lowest and highest hierarchy for microplan + */ + public Map getMicroplanHierarchy(Object mdmsData) { + + String jsonPathForMicroplanHierarchy = JSON_ROOT_PATH + MDMS_ADMIN_CONSOLE_MODULE_NAME + DOT_SEPARATOR + MDMS_MASTER_HIERARCHY_SCHEMA + HIERARCHY_CONFIG_FOR_MICROPLAN; + + List> hierarchyForMicroplan; + + try { + log.info(jsonPathForMicroplanHierarchy); + hierarchyForMicroplan = JsonPath.read(mdmsData, jsonPathForMicroplanHierarchy); + } catch (Exception e) { + log.error(e.getMessage()); + throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); + } + + Map hierarchyMap = new HashMap<>(); + hierarchyMap.put(LOWEST_HIERARCHY_FIELD_FOR_MICROPLAN, hierarchyForMicroplan.get(0).get(LOWEST_HIERARCHY_FIELD_FOR_MICROPLAN).toString().toLowerCase()); + hierarchyMap.put(HIGHEST_HIERARCHY_FIELD_FOR_MICROPLAN, hierarchyForMicroplan.get(0).get(HIGHEST_HIERARCHY_FIELD_FOR_MICROPLAN).toString().toLowerCase()); + + return hierarchyMap; + } + + /** + * Checks if the setup process is completed based on the workflow action in the plan configuration. + * + * @param planConfiguration The plan configuration to check. + * @return true if the setup is completed, otherwise false. + */ + public boolean isSetupCompleted(PlanConfiguration planConfiguration) { + if(!ObjectUtils.isEmpty(planConfiguration.getWorkflow())) + return Objects.equals(planConfiguration.getWorkflow().getAction(), SETUP_COMPLETED_ACTION); + + return false; + } + + /** + * Checks if the setup process is completed based on the workflow action in the plan configuration. + * + * @param planConfiguration The plan configuration to check. + * @return true if the setup is completed, otherwise false. + */ + public boolean checkForEmptyOperationsOrAssumptions(PlanConfiguration planConfiguration) { + return !ObjectUtils.isEmpty(planConfiguration.getOperations()) && !ObjectUtils.isEmpty(planConfiguration.getAssumptions()); + } + + + /** + * Adds or updates the provided fields in the additional details object. + * + * @param additionalDetails the additional details object to be updated. + * @param fieldsToBeUpdated map of field to be updated and it's updated value. + * @return returns the updated additional details object. + */ + + public Map updateFieldInAdditionalDetails(Object additionalDetails, Map fieldsToBeUpdated) { + try { + + // Get or create the additionalDetails as an ObjectNode + ObjectNode objectNode = (additionalDetails == null || additionalDetails instanceof NullNode) + ? objectMapper.createObjectNode() + : objectMapper.convertValue(additionalDetails, ObjectNode.class); + + // Update or add the field in additional details object + fieldsToBeUpdated.forEach((key, value) -> objectNode.set(key, objectMapper.valueToTree(value))); + + // Convert updated ObjectNode back to a Map + return objectMapper.convertValue(objectNode, Map.class); + + } catch (Exception e) { + throw new CustomException(ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_CODE, ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_MESSAGE + e); + } + } + + public void sortOperationsByExecutionOrder(List planConfigurations) { + for (PlanConfiguration planConfiguration : planConfigurations) { + List operations = planConfiguration.getOperations(); + if (!ObjectUtils.isEmpty(operations)) { + operations.sort(Comparator.comparing(Operation::getExecutionOrder)); + } + } + } + +} diff --git a/health-services/plan-service/src/main/java/digit/util/FacilityUtil.java b/health-services/plan-service/src/main/java/digit/util/FacilityUtil.java new file mode 100644 index 00000000000..025d4ea6bb6 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/util/FacilityUtil.java @@ -0,0 +1,84 @@ +package digit.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.config.Configuration; +import digit.web.models.PlanFacilityRequest; +import digit.web.models.facility.FacilityResponse; +import digit.web.models.facility.FacilitySearchCriteria; +import digit.web.models.facility.FacilitySearchRequest; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static digit.config.ServiceConstants.ERROR_WHILE_FETCHING_FROM_FACILITY; + +@Slf4j +@Component +public class FacilityUtil { + + private RestTemplate restTemplate; + private Configuration configs; + private ObjectMapper mapper; + + public FacilityUtil(RestTemplate restTemplate, Configuration configs, ObjectMapper mapper) { + this.restTemplate = restTemplate; + this.configs = configs; + this.mapper = mapper; + } + + public FacilityResponse fetchFacilityData(PlanFacilityRequest planFacilityRequest) { + String baseUri = configs.getFacilityHost()+ configs.getFacilitySearchEndPoint(); + + // Retrieve tenantId from planFacilityRequest + String tenantId = planFacilityRequest.getPlanFacility().getTenantId(); + + // Retrieve the limit and offset from the configuration + int limit = configs.getDefaultLimit(); + int offset = configs.getDefaultOffset(); + + // Use UriComponentsBuilder to construct the URI with query parameters + String uri = UriComponentsBuilder.fromHttpUrl(baseUri) + .queryParam("tenantId", tenantId) + .queryParam("limit", limit) + .queryParam("offset", offset) + .toUriString(); + + FacilitySearchRequest facilitySearchRequest = getFacilitySearchRequest(planFacilityRequest); + FacilityResponse facilityResponse = new FacilityResponse(); + Object response = new HashMap<>(); + try { + // Use postForObject to send the request with the URI containing query params + response = restTemplate.postForObject(uri, facilitySearchRequest, Map.class); + facilityResponse = mapper.convertValue(response , FacilityResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_FACILITY, e); + } + log.info(facilityResponse.toString()); + return facilityResponse; + } + + private FacilitySearchRequest getFacilitySearchRequest(PlanFacilityRequest planFacilityRequest) { + // Retrieve facilityId,requestInfo from planFacilityRequest + String facilityId = planFacilityRequest.getPlanFacility().getFacilityId(); + RequestInfo requestInfo = planFacilityRequest.getRequestInfo(); + + FacilitySearchCriteria searchCriteria = FacilitySearchCriteria.builder() + .id(Collections.singletonList(facilityId)) + .build(); + + return FacilitySearchRequest.builder() + .requestInfo(requestInfo) + .facilitySearchCriteria(searchCriteria) + .build(); + } + + + +} diff --git a/health-services/plan-service/src/main/java/digit/util/MdmsUtil.java b/health-services/plan-service/src/main/java/digit/util/MdmsUtil.java index fb0f6560908..a4979c5da52 100644 --- a/health-services/plan-service/src/main/java/digit/util/MdmsUtil.java +++ b/health-services/plan-service/src/main/java/digit/util/MdmsUtil.java @@ -2,7 +2,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import digit.config.Configuration; + import java.util.LinkedList; + import lombok.extern.slf4j.Slf4j; import org.egov.common.contract.request.RequestInfo; import org.egov.mdms.model.*; @@ -38,11 +40,11 @@ public Object fetchMdmsData(RequestInfo requestInfo, String tenantId) { StringBuilder uri = new StringBuilder(); uri.append(configs.getMdmsHost()).append(configs.getMdmsEndPoint()); MdmsCriteriaReq mdmsCriteriaReq = getMdmsRequest(requestInfo, tenantId); - Object mdmsResponseMap = new HashMap<>(); + Object mdmsResponseMap = new HashMap<>(); MdmsResponse mdmsResponse = new MdmsResponse(); try { - mdmsResponseMap = restTemplate.postForObject(uri.toString(), mdmsCriteriaReq, Map.class); - mdmsResponse = mapper.convertValue(mdmsResponseMap , MdmsResponse.class); + mdmsResponseMap = restTemplate.postForObject(uri.toString(), mdmsCriteriaReq, Map.class); + mdmsResponse = mapper.convertValue(mdmsResponseMap, MdmsResponse.class); } catch (Exception e) { log.error(ERROR_WHILE_FETCHING_FROM_MDMS, e); } @@ -55,18 +57,42 @@ public Object fetchMdmsData(RequestInfo requestInfo, String tenantId) { return result; } + /** + * This method constructs the criteria request for MDMS Api call + * + * @param requestInfo requestInfo from the provided request + * @param tenantId tenant id from the provided request + * @return Returns the mdms criteria request + */ public MdmsCriteriaReq getMdmsRequest(RequestInfo requestInfo, String tenantId) { ModuleDetail assumptionModuleDetail = getPlanModuleDetail(); + ModuleDetail adminConsoleModuleDetail = getAdminConsoleModuleDetail(); List moduleDetails = new LinkedList<>(); moduleDetails.add(assumptionModuleDetail); + moduleDetails.add(adminConsoleModuleDetail); MdmsCriteria mdmsCriteria = MdmsCriteria.builder().moduleDetails(moduleDetails).tenantId(tenantId).build(); return MdmsCriteriaReq.builder().mdmsCriteria(mdmsCriteria).requestInfo(requestInfo).build(); } + private ModuleDetail getAdminConsoleModuleDetail() { + List adminConsoleMasters = new ArrayList<>(); + + MasterDetail hierarchyConfigMaster = MasterDetail.builder().name(MDMS_MASTER_HIERARCHY_SCHEMA).build(); + + adminConsoleMasters.add(hierarchyConfigMaster); + + return ModuleDetail.builder().masterDetails(adminConsoleMasters).moduleName(MDMS_ADMIN_CONSOLE_MODULE_NAME).build(); + } + + /** + * This method constructs module detail object for 'hcm-microplanning' module + * + * @return Returns the module details for 'hcm-microplanning' module + */ private ModuleDetail getPlanModuleDetail() { List assumptionMasterDetails = new ArrayList<>(); diff --git a/health-services/plan-service/src/main/java/digit/util/MdmsV2Util.java b/health-services/plan-service/src/main/java/digit/util/MdmsV2Util.java new file mode 100644 index 00000000000..dad22d39d35 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/util/MdmsV2Util.java @@ -0,0 +1,76 @@ +package digit.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.config.Configuration; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; +import org.springframework.web.client.RestTemplate; +import digit.web.models.mdmsV2.*; + +import java.util.*; + +import static digit.config.ServiceConstants.*; + +@Slf4j +@Component +public class MdmsV2Util { + + private RestTemplate restTemplate; + + private ObjectMapper objectMapper; + + private Configuration configs; + + public MdmsV2Util(RestTemplate restTemplate, ObjectMapper objectMapper, Configuration configs) + { + this.restTemplate = restTemplate; + this.objectMapper = objectMapper; + this.configs = configs; + } + + public List fetchMdmsV2Data(RequestInfo requestInfo, String tenantId, String schemaCode, String uniqueIdentifier) + { + StringBuilder uri = getMdmsV2Uri(); + MdmsCriteriaReqV2 mdmsCriteriaReqV2 = getMdmsV2Request(requestInfo, tenantId, schemaCode, uniqueIdentifier); + MdmsResponseV2 mdmsResponseV2 = null; + try { + mdmsResponseV2 = restTemplate.postForObject(uri.toString(), mdmsCriteriaReqV2, MdmsResponseV2.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_MDMS, e); + } + + if(ObjectUtils.isEmpty(mdmsResponseV2.getMdms())) + { + 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 mdmsResponseV2.getMdms(); + } + + private StringBuilder getMdmsV2Uri() + { + StringBuilder uri = new StringBuilder(); + return uri.append(configs.getMdmsHost()).append(configs.getMdmsV2EndPoint()); + } + + private MdmsCriteriaReqV2 getMdmsV2Request(RequestInfo requestInfo, String tenantId, String schemaCode, String uniqueIdentifier) + { + MdmsCriteriaV2 mdmsCriteriaV2 = MdmsCriteriaV2.builder() + .tenantId(tenantId) + .schemaCode(schemaCode) + .limit(configs.getDefaultLimit()) + .offset(configs.getDefaultOffset()).build(); + + if(!ObjectUtils.isEmpty(uniqueIdentifier)) + mdmsCriteriaV2.setUniqueIdentifiers(Collections.singletonList(uniqueIdentifier)); + + return MdmsCriteriaReqV2.builder() + .requestInfo(requestInfo) + .mdmsCriteriaV2(mdmsCriteriaV2).build(); + } + +} diff --git a/health-services/plan-service/src/main/java/digit/util/QueryUtil.java b/health-services/plan-service/src/main/java/digit/util/QueryUtil.java index 84817b60870..070f442a897 100644 --- a/health-services/plan-service/src/main/java/digit/util/QueryUtil.java +++ b/health-services/plan-service/src/main/java/digit/util/QueryUtil.java @@ -1,7 +1,15 @@ package digit.util; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; +import digit.config.Configuration; +import org.egov.tracer.model.CustomException; +import org.postgresql.util.PGobject; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; +import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -11,10 +19,17 @@ import static digit.config.ServiceConstants.DOT_REGEX; import static digit.config.ServiceConstants.DOT_SEPARATOR; - +@Component public class QueryUtil { - private QueryUtil(){} + private Configuration config; + + private ObjectMapper objectMapper; + + private QueryUtil(Configuration config, ObjectMapper objectMapper) { + this.config = config; + this.objectMapper = objectMapper; + } private static final Gson gson = new Gson(); @@ -22,13 +37,14 @@ private QueryUtil(){} * This method aids in adding "WHERE" clause and "AND" condition depending on preparedStatementList i.e., * if preparedStatementList is empty, it will understand that it is the first clause being added so it * will add "WHERE" to the query and otherwise it will + * * @param query * @param preparedStmtList */ - public static void addClauseIfRequired(StringBuilder query, List preparedStmtList){ - if(preparedStmtList.isEmpty()){ + public void addClauseIfRequired(StringBuilder query, List preparedStmtList) { + if (preparedStmtList.isEmpty()) { query.append(" WHERE "); - }else{ + } else { query.append(" AND "); } } @@ -36,10 +52,11 @@ public static void addClauseIfRequired(StringBuilder query, List prepare /** * This method returns a string with placeholders equal to the number of values that need to be put inside * "IN" clause + * * @param size * @return */ - public static String createQuery(Integer size) { + public String createQuery(Integer size) { StringBuilder builder = new StringBuilder(); IntStream.range(0, size).forEach(i -> { @@ -53,40 +70,48 @@ public static String createQuery(Integer size) { /** * This method adds a set of String values into preparedStatementList + * * @param preparedStmtList * @param ids */ - public static void addToPreparedStatement(List preparedStmtList, Set ids) { + public void addToPreparedStatement(List preparedStmtList, Set ids) { ids.forEach(id -> { preparedStmtList.add(id); }); } + public void addToPreparedStatement(List preparedStmtList, List ids) { + ids.forEach(id -> { + preparedStmtList.add(id); + }); + } /** * This method appends order by clause to the query + * * @param query * @param orderByClause * @return */ - public static String addOrderByClause(String query, String orderByClause){ + public String addOrderByClause(String query, String orderByClause) { return query + orderByClause; } /** * This method prepares partial json string from the filter map to query on jsonb column + * * @param filterMap * @return */ - public static String preparePartialJsonStringFromFilterMap(Map filterMap) { + public String preparePartialJsonStringFromFilterMap(Map filterMap) { Map queryMap = new HashMap<>(); filterMap.keySet().forEach(key -> { - if(key.contains(DOT_SEPARATOR)){ + if (key.contains(DOT_SEPARATOR)) { String[] keyArray = key.split(DOT_REGEX); Map nestedQueryMap = new HashMap<>(); prepareNestedQueryMap(0, keyArray, nestedQueryMap, filterMap.get(key)); queryMap.put(keyArray[0], nestedQueryMap.get(keyArray[0])); - } else{ + } else { queryMap.put(key, filterMap.get(key)); } }); @@ -100,14 +125,15 @@ public static String preparePartialJsonStringFromFilterMap(Map f * Tail recursive method to prepare n-level nested partial json for queries on nested data in * master data. For e.g. , if the key is in the format a.b.c, it will construct a nested json * object of the form - {"a":{"b":{"c": "value"}}} + * * @param index * @param nestedKeyArray * @param currentQueryMap * @param value */ - private static void prepareNestedQueryMap(int index, String[] nestedKeyArray, Map currentQueryMap, String value) { + private void prepareNestedQueryMap(int index, String[] nestedKeyArray, Map currentQueryMap, String value) { // Return when all levels have been reached. - if(index == nestedKeyArray.length) + if (index == nestedKeyArray.length) return; // For the final level simply put the value in the map. @@ -123,4 +149,43 @@ else if (index == nestedKeyArray.length - 1) { prepareNestedQueryMap(index + 1, nestedKeyArray, (Map) currentQueryMap.get(nestedKeyArray[index]), value); } + /** + * This method adds pagination to the query + * + * @param query + * @param preparedStmtList + * @return + */ + public String getPaginatedQuery(String query, List preparedStmtList) { + StringBuilder paginatedQuery = new StringBuilder(query); + + // Append offset + paginatedQuery.append(" OFFSET ? "); + preparedStmtList.add(config.getDefaultOffset()); + + // Append limit + paginatedQuery.append(" LIMIT ? "); + preparedStmtList.add(config.getDefaultLimit()); + + return paginatedQuery.toString(); + } + + /** + * This method is used to extract and parse JSON data into a JsonNode object + * + * @param pGobject postgreSQL specific object + * @return returns a JsonNode + */ + public JsonNode getAdditionalDetail(PGobject pGobject) { + JsonNode additionalDetail = null; + + try { + if (!ObjectUtils.isEmpty(pGobject)) { + additionalDetail = objectMapper.readTree(pGobject.getValue()); + } + } catch (IOException e) { + throw new CustomException("PARSING_ERROR", "Failed to parse additionalDetails object"); + } + return additionalDetail; + } } diff --git a/health-services/plan-service/src/main/java/digit/util/ServiceUtil.java b/health-services/plan-service/src/main/java/digit/util/ServiceUtil.java index 51959990534..19c7bebeea7 100644 --- a/health-services/plan-service/src/main/java/digit/util/ServiceUtil.java +++ b/health-services/plan-service/src/main/java/digit/util/ServiceUtil.java @@ -8,16 +8,5 @@ @Component public class ServiceUtil { - /** - * Validates the given input string against the provided regex pattern. - * - * @param patternString the regex pattern to validate against - * @param inputString the input string to be validated - * @return true if the input string matches the regex pattern, false otherwise - */ - public Boolean validateStringAgainstRegex(String patternString, String inputString) { - Pattern pattern = Pattern.compile(patternString); - Matcher matcher = pattern.matcher(inputString); - return matcher.matches(); - } + } diff --git a/health-services/plan-service/src/main/java/digit/util/UserUtil.java b/health-services/plan-service/src/main/java/digit/util/UserUtil.java new file mode 100644 index 00000000000..0e60073313e --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/util/UserUtil.java @@ -0,0 +1,73 @@ +package digit.util; + +import digit.config.Configuration; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.user.UserDetailResponse; +import org.egov.common.contract.user.UserSearchRequest; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.util.Collections; + +import static digit.config.ServiceConstants.ERROR_WHILE_FETCHING_FROM_USER_SERVICE; + +@Slf4j +@Component +public class UserUtil { + + private Configuration config; + + private RestTemplate restTemplate; + + public UserUtil(RestTemplate restTemplate, Configuration config) { + this.restTemplate = restTemplate; + this.config = config; + } + + /** + * This method fetches user details from User Service for the provided search request + * + * @param userSearchReq Search request to search for user detail response + */ + public UserDetailResponse fetchUserDetail(UserSearchRequest userSearchReq) { + + UserDetailResponse userDetailResponse = new UserDetailResponse(); + + try { + userDetailResponse = restTemplate.postForObject(getUserServiceUri().toString(), userSearchReq, UserDetailResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_USER_SERVICE, e); + } + + return userDetailResponse; + } + + /** + * This method creates the uri for User service + * + * @return uri for user detail search + */ + private StringBuilder getUserServiceUri() { + return new StringBuilder().append(config.getUserServiceHost()).append(config.getUserSearchEndPoint()); + } + + /** + * This method creates the search request body for user detail search + * + * @param requestInfo Request Info from the request body + * @param employeeId Employee id for the provided plan employee assignment request + * @param tenantId Tenant id from the plan employee assignment request + * @return Search request body for user detail search + */ + public UserSearchRequest getUserSearchReq(RequestInfo requestInfo, String employeeId, String tenantId) { + + UserSearchRequest userSearchRequest = new UserSearchRequest(); + + userSearchRequest.setRequestInfo(requestInfo); + userSearchRequest.setTenantId(tenantId); + userSearchRequest.setUuid(Collections.singletonList(employeeId)); + + return userSearchRequest; + } +} diff --git a/health-services/plan-service/src/main/java/digit/web/controllers/PlanConfigController.java b/health-services/plan-service/src/main/java/digit/web/controllers/PlanConfigController.java index 4729cdd736e..d50610832e9 100644 --- a/health-services/plan-service/src/main/java/digit/web/controllers/PlanConfigController.java +++ b/health-services/plan-service/src/main/java/digit/web/controllers/PlanConfigController.java @@ -3,7 +3,6 @@ import digit.service.PlanConfigurationService; import digit.util.ResponseInfoFactory; -import digit.web.models.PlanConfiguration; import digit.web.models.PlanConfigurationRequest; import digit.web.models.PlanConfigurationResponse; import digit.web.models.PlanConfigurationSearchRequest; diff --git a/health-services/plan-service/src/main/java/digit/web/controllers/PlanController.java b/health-services/plan-service/src/main/java/digit/web/controllers/PlanController.java index 2381b009d40..43f50e6a5af 100644 --- a/health-services/plan-service/src/main/java/digit/web/controllers/PlanController.java +++ b/health-services/plan-service/src/main/java/digit/web/controllers/PlanController.java @@ -30,7 +30,7 @@ public PlanController(PlanService planService) { * @return */ @RequestMapping(value = "/_create", method = RequestMethod.POST) - public ResponseEntity createPost(@Valid @RequestBody PlanRequest body) { + public ResponseEntity create(@Valid @RequestBody PlanRequest body) { PlanResponse planResponse = planService.createPlan(body); return ResponseEntity.status(HttpStatus.ACCEPTED).body(planResponse); } @@ -41,7 +41,7 @@ public ResponseEntity createPost(@Valid @RequestBody PlanRequest b * @return */ @RequestMapping(value = "/_search", method = RequestMethod.POST) - public ResponseEntity searchPost(@Valid @RequestBody PlanSearchRequest body) { + public ResponseEntity search(@Valid @RequestBody PlanSearchRequest body) { PlanResponse planResponse = planService.searchPlan(body); return ResponseEntity.status(HttpStatus.OK).body(planResponse); } @@ -52,9 +52,20 @@ public ResponseEntity searchPost(@Valid @RequestBody PlanSearchReq * @return */ @RequestMapping(value = "/_update", method = RequestMethod.POST) - public ResponseEntity updatePost(@Valid @RequestBody PlanRequest body) { + public ResponseEntity update(@Valid @RequestBody PlanRequest body) { PlanResponse planResponse = planService.updatePlan(body); return ResponseEntity.status(HttpStatus.ACCEPTED).body(planResponse); } + /** + * Request handler for serving bulk plan update requests + * @param body + * @return + */ + @RequestMapping(value = "/bulk/_update", method = RequestMethod.POST) + public ResponseEntity bulkUpdate(@Valid @RequestBody BulkPlanRequest body) { + PlanResponse planResponse = planService.bulkUpdate(body); + return ResponseEntity.status(HttpStatus.CREATED).body(planResponse); + } + } diff --git a/health-services/plan-service/src/main/java/digit/web/controllers/PlanEmployeeController.java b/health-services/plan-service/src/main/java/digit/web/controllers/PlanEmployeeController.java new file mode 100644 index 00000000000..db707f9e872 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/controllers/PlanEmployeeController.java @@ -0,0 +1,62 @@ +package digit.web.controllers; + +import digit.service.PlanEmployeeService; +import digit.web.models.*; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +@Controller +public class PlanEmployeeController { + + PlanEmployeeService planEmployeeService; + + public PlanEmployeeController(PlanEmployeeService planEmployeeService) + { + this.planEmployeeService = planEmployeeService; + } + + /** + * Request handler for serving plan employee assignment create requests + * @param body + * @return + */ + @RequestMapping(value = "/employee/_create", method = RequestMethod.POST) + public ResponseEntity employeeCreatePost(@Parameter(in = ParameterIn.DEFAULT, description = "", schema = @Schema()) @Valid @RequestBody PlanEmployeeAssignmentRequest body) { + + PlanEmployeeAssignmentResponse response = planEmployeeService.create(body); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + + } + + /** + * Request handler for serving plan employee assignment search requests + * @param body + * @return + */ + @RequestMapping(value = "/employee/_search", method = RequestMethod.POST) + public ResponseEntity employeeSearchPost(@Parameter(in = ParameterIn.DEFAULT, description = "", schema = @Schema()) @Valid @RequestBody PlanEmployeeAssignmentSearchRequest body) { + + PlanEmployeeAssignmentResponse response = planEmployeeService.search(body); + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + /** + * Request handler for serving plan employee assignment update requests + * @param body + * @return + */ + @RequestMapping(value = "/employee/_update", method = RequestMethod.POST) + public ResponseEntity employeeUpdatePost(@Parameter(in = ParameterIn.DEFAULT, description = "", schema = @Schema()) @Valid @RequestBody PlanEmployeeAssignmentRequest body) { + + PlanEmployeeAssignmentResponse response = planEmployeeService.update(body); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } +} diff --git a/health-services/plan-service/src/main/java/digit/web/controllers/PlanFacilityController.java b/health-services/plan-service/src/main/java/digit/web/controllers/PlanFacilityController.java new file mode 100644 index 00000000000..bca90f5c544 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/controllers/PlanFacilityController.java @@ -0,0 +1,61 @@ +package digit.web.controllers; + +import digit.service.PlanFacilityService; +import digit.web.models.*; +import jakarta.validation.Valid; +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; + +@Validated +@Controller +@RequestMapping("plan") +public class PlanFacilityController { + + private PlanFacilityService planFacilityService; + + public PlanFacilityController(PlanFacilityService planFacilityService) { + this.planFacilityService = planFacilityService; + } + + /** + * Request handler for serving plan facility create requests + * + * @param planFacilityRequest + * @return + */ + @RequestMapping(value = "/facility/_create", method = RequestMethod.POST) + public ResponseEntity createPlanFacility(@Valid @RequestBody PlanFacilityRequest planFacilityRequest) { + PlanFacilityResponse planFacilityResponse = planFacilityService.createPlanFacility(planFacilityRequest); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(planFacilityResponse); + } + + /** + * Request handler for serving plan facility search requests + * + * @param planFacilityRequest + * @return + */ + @RequestMapping(value = "/facility/_search", method = RequestMethod.POST) + public ResponseEntity searchPlanFacility(@Valid @RequestBody PlanFacilitySearchRequest planFacilityRequest) { + PlanFacilityResponse planFacilityResponse = planFacilityService.searchPlanFacility(planFacilityRequest); + return ResponseEntity.status(HttpStatus.OK).body(planFacilityResponse); + } + + /** + * Request handler for serving plan facility update requests + * + * @param planFacilityRequest + * @return + */ + @RequestMapping(value = "/facility/_update", method = RequestMethod.POST) + public ResponseEntity updatePlanFacility(@Valid @RequestBody PlanFacilityRequest planFacilityRequest) { + PlanFacilityResponse planFacilityResponse = planFacilityService.updatePlanFacility(planFacilityRequest); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(planFacilityResponse); + } + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/Assumption.java b/health-services/plan-service/src/main/java/digit/web/models/Assumption.java index a4b7e3ad01f..81486894093 100644 --- a/health-services/plan-service/src/main/java/digit/web/models/Assumption.java +++ b/health-services/plan-service/src/main/java/digit/web/models/Assumption.java @@ -38,10 +38,19 @@ public class Assumption { @NotNull @Valid @DecimalMin(value = "0.01", inclusive = true, message = "The Assumption value must be greater than 0") - @DecimalMax(value = "9999999999.99", inclusive = true, message = "The assumption value must not exceed 10 digits in total, including up to 2 decimal places.") - @Digits(integer = 10, fraction = 2, message = "The Assumption value must have up to 10 digits and up to 2 decimal points") + @DecimalMax(value = "1000.00", inclusive = true, message = "The assumption value must not exceed 4 digits in total, including up to 2 decimal places.") + @Digits(integer = 4, fraction = 2, message = "The Assumption value must have up to 10 digits and up to 2 decimal points") private BigDecimal value = null; + @JsonProperty("source") + @NotNull(message = "Source cannot be null. Please specify a valid source.") + private Source source = null; + + @JsonProperty("category") + @NotNull + @Size(min = 2, max = 64) + private String category = null; + @JsonProperty("active") @NotNull private Boolean active = true; diff --git a/health-services/plan-service/src/main/java/digit/web/models/BulkPlanRequest.java b/health-services/plan-service/src/main/java/digit/web/models/BulkPlanRequest.java new file mode 100644 index 00000000000..f12bbc1ee8f --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/BulkPlanRequest.java @@ -0,0 +1,33 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +import java.util.List; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BulkPlanRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Plans") + @Valid + @NotNull + @NotEmpty + private List plans = null; + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/Operation.java b/health-services/plan-service/src/main/java/digit/web/models/Operation.java index fbc647cfc1d..b12c44341fb 100644 --- a/health-services/plan-service/src/main/java/digit/web/models/Operation.java +++ b/health-services/plan-service/src/main/java/digit/web/models/Operation.java @@ -40,14 +40,30 @@ public class Operation { @JsonProperty("assumptionValue") @NotNull - @Size(min = 2, max = 256) + @Size(min = 1, max = 256) private String assumptionValue = null; @JsonProperty("output") @NotNull - @Size(min = 1, max = 64) + @Size(min = 1, max = 256) private String output = null; + @JsonProperty("showOnEstimationDashboard") + @NotNull + private Boolean showOnEstimationDashboard = true; + + @JsonProperty("source") + @NotNull(message = "Source cannot be null. Please specify a valid source.") + private Source source = null; + + @JsonProperty("category") + @NotNull + @Size(min = 2, max = 64) + private String category = null; + + @JsonProperty("executionOrder") + private Integer executionOrder = null; + @JsonProperty("active") @NotNull private Boolean active = true; diff --git a/health-services/plan-service/src/main/java/digit/web/models/Pagination.java b/health-services/plan-service/src/main/java/digit/web/models/Pagination.java new file mode 100644 index 00000000000..6d3fd64df77 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/Pagination.java @@ -0,0 +1,35 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Pagination + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Pagination { + + @JsonIgnore + private String sortBy; + + @JsonIgnore + private String sortOrder; + + @JsonProperty("limit") + @Min(1) + @Max(50) + private Integer limit; + + @JsonProperty("offset") + @Min(0) + private Integer offset; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/Plan.java b/health-services/plan-service/src/main/java/digit/web/models/Plan.java index f1fb59a400e..3ff0e8ce87d 100644 --- a/health-services/plan-service/src/main/java/digit/web/models/Plan.java +++ b/health-services/plan-service/src/main/java/digit/web/models/Plan.java @@ -1,12 +1,15 @@ package digit.web.models; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.List; +import java.util.Map; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; import org.egov.common.contract.models.AuditDetails; +import org.egov.common.contract.models.Workflow; import org.springframework.validation.annotation.Validated; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; @@ -35,14 +38,21 @@ public class Plan { @Size(min = 1, max = 64) private String locality = null; - @JsonProperty("executionPlanId") + @JsonProperty("campaignId") @Size(max = 64) - private String executionPlanId = null; + private String campaignId = null; @JsonProperty("planConfigurationId") @Size(max = 64) private String planConfigurationId = null; + @JsonProperty("status") + @Size(max = 64) + private String status = null; + + @JsonProperty("assignee") + private List assignee = null; + @JsonProperty("additionalDetails") private Object additionalDetails = null; @@ -61,4 +71,20 @@ public class Plan { @JsonProperty("auditDetails") private AuditDetails auditDetails = null; + @JsonProperty("jurisdictionMapping") + private Map jurisdictionMapping; + + @JsonIgnore + private String boundaryAncestralPath = null; + + @JsonIgnore + private boolean isRequestFromResourceEstimationConsumer; + + @JsonIgnore + private List assigneeJurisdiction; + + @JsonProperty("workflow") + @Valid + private Workflow workflow; + } diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanConfiguration.java b/health-services/plan-service/src/main/java/digit/web/models/PlanConfiguration.java index 9032da0bfed..50c43741d48 100644 --- a/health-services/plan-service/src/main/java/digit/web/models/PlanConfiguration.java +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanConfiguration.java @@ -1,9 +1,6 @@ package digit.web.models; -import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonValue; -import jakarta.validation.constraints.NotEmpty; import java.util.ArrayList; import java.util.List; import jakarta.validation.Valid; @@ -11,6 +8,7 @@ import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Pattern; import org.egov.common.contract.models.AuditDetails; +import org.egov.common.contract.models.Workflow; import org.springframework.validation.annotation.Validated; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; @@ -41,50 +39,40 @@ public class PlanConfiguration { @Size(min = 3, max = 128) private String name = null; - @JsonProperty("executionPlanId") + @JsonProperty("campaignId") @NotNull @Size(min = 2, max = 64) - @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Execution Plan Id must not contain only special characters") - private String executionPlanId = null; + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Campaign Id must not contain only special characters") + private String campaignId = null; @JsonProperty("status") - @NotNull - private StatusEnum status = null; + private String 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 - } + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("workflow") + @Valid + private Workflow workflow; + } diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationSearchCriteria.java b/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationSearchCriteria.java index ab7c827c49a..1f0b8f6be6f 100644 --- a/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationSearchCriteria.java +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationSearchCriteria.java @@ -1,6 +1,5 @@ package digit.web.models; -import jakarta.validation.Valid; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; @@ -12,6 +11,8 @@ import lombok.Data; import lombok.Builder; +import java.util.List; + /** * PlanConfigurationSearchCriteria */ @@ -30,14 +31,17 @@ public class PlanConfigurationSearchCriteria { @JsonProperty("id") private String id = null; + @JsonProperty("ids") + private List ids = null; + @JsonProperty("name") private String name = null; - @JsonProperty("executionPlanId") - private String executionPlanId = null; + @JsonProperty("campaignId") + private String campaignId = null; @JsonProperty("status") - private String status = null; + private List status = null; @JsonProperty("userUuid") private String userUuid = null; @@ -50,5 +54,4 @@ public class PlanConfigurationSearchCriteria { @Min(1) @Max(50) private Integer limit; - } diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanDTO.java b/health-services/plan-service/src/main/java/digit/web/models/PlanDTO.java new file mode 100644 index 00000000000..f56569c1349 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanDTO.java @@ -0,0 +1,90 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonIgnore; +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.models.AuditDetails; +import org.egov.common.contract.models.Workflow; +import org.springframework.validation.annotation.Validated; + +import java.util.List; +import java.util.Map; + +/** + * Plan + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanDTO { + + @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("campaignId") + @Size(max = 64) + private String campaignId = null; + + @JsonProperty("planConfigurationId") + @Size(max = 64) + private String planConfigurationId = null; + + @JsonProperty("status") + @Size(max = 64) + private String status = null; + + @JsonProperty("assignee") + private String assignee = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("jurisdictionMapping") + private Map jurisdictionMapping; + + @JsonProperty("activities") + @Valid + private List activities; + + @JsonProperty("resources") + @Valid + private List resources; + + @JsonProperty("targets") + @Valid + private List targets; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("boundaryAncestralPath") + private String boundaryAncestralPath = null; + + @JsonIgnore + private Boolean partnerAssignmentValidationEnabled; + + @JsonIgnore + private List assigneeJurisdiction; + + @JsonProperty("workflow") + @Valid + private Workflow workflow; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignment.java b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignment.java new file mode 100644 index 00000000000..c27b1e1eb1b --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignment.java @@ -0,0 +1,71 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Set; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +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; + +/** + * PlanEmployeeAssignment + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignment { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("planConfigurationId") + @NotNull + @Size(min = 2, max = 64) + private String planConfigurationId = null; + + @JsonProperty("planConfigurationName") + private String planConfigurationName = null; + + @JsonProperty("employeeId") + @NotNull + @Size(min = 2, max = 64) + private String employeeId = null; + + @JsonProperty("role") + @NotNull + @Size(min = 2, max = 64) + private String role = null; + + @JsonProperty("hierarchyLevel") + @Size(min = 2, max = 64) + private String hierarchyLevel = null; + + @JsonProperty("jurisdiction") + @Valid + @NotEmpty + private Set jurisdiction = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("active") + private Boolean active = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentDTO.java b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentDTO.java new file mode 100644 index 00000000000..555d916c1ff --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentDTO.java @@ -0,0 +1,69 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +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; + +/** + * PlanEmployeeAssignmentDTO + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignmentDTO { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("planConfigurationId") + @NotNull + @Size(min = 2, max = 64) + private String planConfigurationId = null; + + @JsonProperty("planConfigurationName") + private String planConfigurationName = null; + + @JsonProperty("employeeId") + @NotNull + @Size(min = 2, max = 64) + private String employeeId = null; + + @JsonProperty("role") + @NotNull + @Size(min = 2, max = 64) + private String role = null; + + @JsonProperty("hierarchyLevel") + @Size(min = 2, max = 64) + private String hierarchyLevel = null; + + @JsonProperty("jurisdiction") + @Valid + @NotEmpty + private String jurisdiction = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("active") + private Boolean active = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentRequest.java b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentRequest.java new file mode 100644 index 00000000000..4361b16dde2 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentRequest.java @@ -0,0 +1,30 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + + +/** + * PlanEmployeeAssignmentRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignmentRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("PlanEmployeeAssignment") + @Valid + private PlanEmployeeAssignment planEmployeeAssignment = null; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentRequestDTO.java b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentRequestDTO.java new file mode 100644 index 00000000000..f21bc83a3e8 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentRequestDTO.java @@ -0,0 +1,30 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + + +/** + * PlanEmployeeAssignmentRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignmentRequestDTO { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("PlanEmployeeAssignment") + @Valid + private PlanEmployeeAssignmentDTO planEmployeeAssignmentDTO = null; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentResponse.java b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentResponse.java new file mode 100644 index 00000000000..6c6ecdc516c --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentResponse.java @@ -0,0 +1,36 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import jakarta.validation.Valid; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + + +/** + * PlanEmployeeAssignmentResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignmentResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("PlanEmployeeAssignment") + @Valid + private List planEmployeeAssignment = null; + + @JsonProperty("TotalCount") + @Valid + private Integer totalCount = null; +} + diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentSearchCriteria.java b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentSearchCriteria.java new file mode 100644 index 00000000000..22008b64135 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentSearchCriteria.java @@ -0,0 +1,72 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import java.util.Set; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import org.springframework.validation.annotation.Validated; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * PlanEmployeeAssignmentSearchCriteria + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignmentSearchCriteria { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @Size(min = 2, max = 100) + @NotNull + private String tenantId = null; + + @JsonProperty("employeeId") + private List employeeId = null; + + @JsonProperty("planConfigurationId") + @Size(max = 64) + private String planConfigurationId = null; + + @JsonProperty("planConfigurationName") + private String planConfigurationName = null; + + @JsonProperty("planConfigurationStatus") + private Set planConfigurationStatus = null; + + @JsonProperty("role") + @Valid + private List role = null; + + @JsonProperty("hierarchyLevel") + private String hierarchyLevel = null; + + @JsonProperty("jurisdiction") + @Valid + private List jurisdiction = null; + + @JsonProperty("active") + @Builder.Default + private Boolean active = Boolean.TRUE; + + @JsonProperty("filterUniqueByPlanConfig") + @Builder.Default + private Boolean filterUniqueByPlanConfig = Boolean.FALSE; + + @JsonProperty("offset") + private Integer offset = null; + + @JsonProperty("limit") + private Integer limit = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentSearchRequest.java b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentSearchRequest.java new file mode 100644 index 00000000000..a8b3a40a41f --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanEmployeeAssignmentSearchRequest.java @@ -0,0 +1,29 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * PlanEmployeeAssignmentSearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanEmployeeAssignmentSearchRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("PlanEmployeeAssignmentSearchCriteria") + @Valid + private PlanEmployeeAssignmentSearchCriteria planEmployeeAssignmentSearchCriteria = null; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanFacility.java b/health-services/plan-service/src/main/java/digit/web/models/PlanFacility.java new file mode 100644 index 00000000000..87c024324ac --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanFacility.java @@ -0,0 +1,92 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonIgnore; +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.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Plan Facility + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanFacility { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("planConfigurationId") + @NotNull + @Size(max = 64) + private String planConfigurationId = null; + + @JsonProperty("planConfigurationName") + private String planConfigurationName = null; + + @JsonProperty("boundaryAncestralPath") + private String boundaryAncestralPath = null; + + @JsonProperty("facilityId") + @NotNull + @Size(max = 64) + private String facilityId = null; + + @JsonProperty("facilityName") + private String facilityName = null; + + @JsonProperty("residingBoundary") + @NotNull + @Size(min = 1, max = 64) + private String residingBoundary = null; + + @JsonProperty("serviceBoundaries") + @NotNull + @Valid + private List serviceBoundaries; + + @JsonIgnore + private List initiallySetServiceBoundaries; + + @JsonProperty("jurisdictionMapping") + private Map jurisdictionMapping; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("active") + @NotNull + private Boolean active = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + public PlanFacility addServiceBoundariesItem(String serviceBoundariesItem) { + if (this.serviceBoundaries == null) { + this.serviceBoundaries = new ArrayList<>(); + } + this.serviceBoundaries.add(serviceBoundariesItem); + return this; + } + + + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityDTO.java b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityDTO.java new file mode 100644 index 00000000000..771c602f760 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityDTO.java @@ -0,0 +1,79 @@ +package digit.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.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import java.util.List; +import java.util.Map; + +/** + * Plan Facility DTO + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanFacilityDTO { + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("planConfigurationId") + @NotNull + @Size(max = 64) + private String planConfigurationId = null; + + @JsonProperty("planConfigurationName") + private String planConfigurationName = null; + + @JsonProperty("boundaryAncestralPath") + private String boundaryAncestralPath = null; + + @JsonProperty("facilityId") + @NotNull + @Size(max = 64) + private String facilityId = null; + + @JsonProperty("residingBoundary") + @NotNull + @Size(min = 1, max = 64) + private String residingBoundary = null; + + // Changed List to String to store as JSON + @JsonProperty("serviceBoundaries") + @NotNull + @Size(min = 1) + private String serviceBoundaries = null; // Store as JSON string + + @JsonProperty("initiallySetServiceBoundaries") + private List initiallySetServiceBoundaries; + + @JsonProperty("facilityName") + private String facilityName = null; + + @JsonProperty("jurisdictionMapping") + private Map jurisdictionMapping; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("active") + @NotNull + private Boolean active = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityRequest.java b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityRequest.java new file mode 100644 index 00000000000..9eb2652d0a7 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityRequest.java @@ -0,0 +1,33 @@ +package digit.web.models; + +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.springframework.validation.annotation.Validated; + +/** + * PlanFacilityRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanFacilityRequest { + + @JsonProperty("RequestInfo") + @Valid + @NotNull + private RequestInfo requestInfo; + + @JsonProperty("PlanFacility") + @Valid + @NotNull + private PlanFacility planFacility; + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityRequestDTO.java b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityRequestDTO.java new file mode 100644 index 00000000000..a78b2ba0047 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityRequestDTO.java @@ -0,0 +1,33 @@ +package digit.web.models; + +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.springframework.validation.annotation.Validated; + +/** + * PlanFacilityRequestDTO + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanFacilityRequestDTO { + + @JsonProperty("RequestInfo") + @Valid + @NotNull + private RequestInfo requestInfo; + + @JsonProperty("PlanFacility") + @Valid + @NotNull + private PlanFacilityDTO planFacilityDTO; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityResponse.java b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityResponse.java new file mode 100644 index 00000000000..1ac3db052c6 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilityResponse.java @@ -0,0 +1,33 @@ +package digit.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.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; +import java.util.List; + +/** + * PlanFacilityResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanFacilityResponse { + + @JsonProperty("ResponseInfo") + private ResponseInfo responseInfo = null; + + @JsonProperty("PlanFacility") + @Valid + private List planFacility = null; + + @JsonProperty("TotalCount") + @Valid + private Integer totalCount = null; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanFacilitySearchCriteria.java b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilitySearchCriteria.java new file mode 100644 index 00000000000..a5a4e49c42c --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilitySearchCriteria.java @@ -0,0 +1,64 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanFacilitySearchCriteria { + + @JsonProperty("ids") + private Set ids = null; + + @JsonProperty("tenantId") + @NotNull + private String tenantId = null; + + @JsonProperty("planConfigurationId") + @NotNull + private String planConfigurationId = null; + + @JsonProperty("planConfigurationName") + private String planConfigurationName = null; + + @JsonProperty("facilityName") + private String facilityName = null; + + @JsonProperty("facilityStatus") + private String facilityStatus = null; + + @JsonProperty("facilityType") + private String facilityType = null; + + @JsonProperty("residingBoundaries") + private List residingBoundaries = null; + + @JsonProperty("jurisdiction") + private List jurisdiction = null; + + @JsonProperty("facilityId") + private String facilityId = null; + + @JsonProperty("offset") + private Integer offset = null; + + @JsonProperty("limit") + private Integer limit = null; + + @JsonIgnore + private Map filtersMap = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanFacilitySearchRequest.java b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilitySearchRequest.java new file mode 100644 index 00000000000..65517af3d18 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanFacilitySearchRequest.java @@ -0,0 +1,34 @@ +package digit.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; + +import javax.validation.constraints.NotNull; + +/** + * PlanFacilitySearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanFacilitySearchRequest { + + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("PlanFacilitySearchCriteria") + @NotNull + @Valid + private PlanFacilitySearchCriteria planFacilitySearchCriteria = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanRequestDTO.java b/health-services/plan-service/src/main/java/digit/web/models/PlanRequestDTO.java new file mode 100644 index 00000000000..1b60fca0696 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanRequestDTO.java @@ -0,0 +1,29 @@ +package digit.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 PlanRequestDTO { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Plan") + @Valid + private PlanDTO planDTO = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanResponse.java b/health-services/plan-service/src/main/java/digit/web/models/PlanResponse.java index bf08ba0059c..51e11ec94a5 100644 --- a/health-services/plan-service/src/main/java/digit/web/models/PlanResponse.java +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanResponse.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.util.List; +import java.util.Map; + import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; import jakarta.validation.Valid; @@ -28,4 +30,12 @@ public class PlanResponse { @Valid private List plan = null; + @JsonProperty("TotalCount") + @Valid + private Integer totalCount = null; + + @JsonProperty("StatusCount") + @Valid + private Map statusCount = null; + } diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanSearchCriteria.java b/health-services/plan-service/src/main/java/digit/web/models/PlanSearchCriteria.java index 6e9cc9449d1..357b306fa8f 100644 --- a/health-services/plan-service/src/main/java/digit/web/models/PlanSearchCriteria.java +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanSearchCriteria.java @@ -1,15 +1,16 @@ package digit.web.models; -import java.util.Set; - import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import org.springframework.validation.annotation.Validated; import lombok.AllArgsConstructor; -import lombok.NoArgsConstructor; -import lombok.Data; import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import java.util.List; +import java.util.Set; /** * PlanSearchCriteria @@ -29,14 +30,24 @@ public class PlanSearchCriteria { private String tenantId = null; @JsonProperty("locality") - private String locality = null; + private List locality = null; - @JsonProperty("executionPlanId") - private String executionPlanId = null; + @JsonProperty("campaignId") + private String campaignId = null; @JsonProperty("planConfigurationId") private String planConfigurationId = null; + @JsonProperty("status") + private String status = null; + + @JsonProperty("assignee") + private String assignee = null; + + @JsonProperty("jurisdiction") + @Valid + private List jurisdiction = null; + @JsonProperty("offset") private Integer offset = null; diff --git a/health-services/plan-service/src/main/java/digit/web/models/RequestInfoWrapper.java b/health-services/plan-service/src/main/java/digit/web/models/RequestInfoWrapper.java new file mode 100644 index 00000000000..9613a753b82 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/RequestInfoWrapper.java @@ -0,0 +1,18 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Component +public class RequestInfoWrapper { + + @JsonProperty("RequestInfo") + private RequestInfo requestInfo; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/Resource.java b/health-services/plan-service/src/main/java/digit/web/models/Resource.java index 0b64b3108c1..d0d8ce2500b 100644 --- a/health-services/plan-service/src/main/java/digit/web/models/Resource.java +++ b/health-services/plan-service/src/main/java/digit/web/models/Resource.java @@ -25,7 +25,7 @@ public class Resource { @JsonProperty("resourceType") @NotNull - @Size(min = 2, max = 256) + @Size(min = 1, max = 256) private String resourceType = null; @JsonProperty("estimatedNumber") diff --git a/health-services/plan-service/src/main/java/digit/web/models/Source.java b/health-services/plan-service/src/main/java/digit/web/models/Source.java new file mode 100644 index 00000000000..e58bfba27be --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/Source.java @@ -0,0 +1,5 @@ +package digit.web.models; + +public enum Source { + MDMS, CUSTOM, VEHICLE; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundarySearchResponse.java b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundarySearchResponse.java new file mode 100644 index 00000000000..7f92e1f53c8 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundarySearchResponse.java @@ -0,0 +1,42 @@ +package digit.web.models.boundary; + +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; + +/** + * 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/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchy.java b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchy.java new file mode 100644 index 00000000000..45ab5a19141 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchy.java @@ -0,0 +1,30 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryTypeHierarchy + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchy { + + @JsonProperty("boundaryType") + private String boundaryType = null; + + @JsonProperty("parentBoundaryType") + private String parentBoundaryType = null; + + @JsonProperty("active") + private Boolean active = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyDefinition.java b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyDefinition.java new file mode 100644 index 00000000000..6faf8ac0b49 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyDefinition.java @@ -0,0 +1,45 @@ +package digit.web.models.boundary; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import jakarta.validation.Valid; +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; + +import java.util.List; + +/** + * BoundaryTypeHierarchyDefinition + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchyDefinition { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("hierarchyType") + private String hierarchyType = null; + + @JsonProperty("boundaryHierarchy") + @Valid + private List boundaryHierarchy = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("boundaryHierarchyJsonNode") + private JsonNode boundaryHierarchyJsonNode = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyResponse.java b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyResponse.java new file mode 100644 index 00000000000..6372620c43c --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchyResponse.java @@ -0,0 +1,36 @@ +package digit.web.models.boundary; + +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.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * BoundaryTypeHierarchyResponse + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchyResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("totalCount") + private Integer totalCount = null; + + @JsonProperty("BoundaryHierarchy") + @Valid + private List boundaryHierarchy = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchCriteria.java b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchCriteria.java new file mode 100644 index 00000000000..ba335f7f037 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchCriteria.java @@ -0,0 +1,39 @@ +package digit.web.models.boundary; + +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; + +/** + * BoundaryTypeHierarchySearchCriteria + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchySearchCriteria { + + @JsonProperty("tenantId") + @Size(min = 1, max = 100) + @NotNull + private String tenantId = null; + + @JsonProperty("hierarchyType") + @Size(min = 1, max = 100) + private String hierarchyType = null; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} + diff --git a/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchRequest.java b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchRequest.java new file mode 100644 index 00000000000..46cb6eb463a --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/boundary/BoundaryTypeHierarchySearchRequest.java @@ -0,0 +1,31 @@ +package digit.web.models.boundary; + +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; + +/** + * BoundaryTypeHierarchySearchRequest + */ +@Validated +@jakarta.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryTypeHierarchySearchRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("BoundaryTypeHierarchySearchCriteria") + @Valid + private BoundaryTypeHierarchySearchCriteria boundaryTypeHierarchySearchCriteria = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/boundary/EnrichedBoundary.java b/health-services/plan-service/src/main/java/digit/web/models/boundary/EnrichedBoundary.java new file mode 100644 index 00000000000..c42af3737ce --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/boundary/EnrichedBoundary.java @@ -0,0 +1,42 @@ +package digit.web.models.boundary; + +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; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 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/plan-service/src/main/java/digit/web/models/boundary/HierarchyRelation.java b/health-services/plan-service/src/main/java/digit/web/models/boundary/HierarchyRelation.java new file mode 100644 index 00000000000..7a3e26f6595 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/boundary/HierarchyRelation.java @@ -0,0 +1,34 @@ +package digit.web.models.boundary; + +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 java.util.List; + +/** + * 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/plan-service/src/main/java/digit/web/models/census/AdditionalField.java b/health-services/plan-service/src/main/java/digit/web/models/census/AdditionalField.java new file mode 100644 index 00000000000..65ae4222831 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/census/AdditionalField.java @@ -0,0 +1,48 @@ +package digit.web.models.census; + +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.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; + +/** + * AdditionalField + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AdditionalField { + + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("key") + @Valid + @NotNull + private String key = null; + + @JsonProperty("value") + @Valid + @NotNull + private BigDecimal value = null; + + @JsonProperty("showOnUi") + private Boolean showOnUi = Boolean.TRUE; + + @JsonProperty("editable") + private Boolean editable = Boolean.TRUE; + + @JsonProperty("order") + private Integer order = null; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/census/Census.java b/health-services/plan-service/src/main/java/digit/web/models/census/Census.java new file mode 100644 index 00000000000..e8f384d1e98 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/census/Census.java @@ -0,0 +1,139 @@ +package digit.web.models.census; + + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +import java.util.List; + +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.models.AuditDetails; +import org.egov.common.contract.models.Workflow; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; + + +/** + * Census + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Census { + + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("tenantId") + @NotNull + private String tenantId = null; + + @JsonProperty("hierarchyType") + @NotNull + private String hierarchyType = null; + + @JsonProperty("boundaryCode") + @NotNull + private String boundaryCode = null; + + @JsonProperty("assignee") + @Size(max = 64) + private String assignee = null; + + @JsonProperty("status") + @Size(max = 64) + private String status = null; + + @JsonProperty("type") + @NotNull + private TypeEnum type = null; + + @JsonProperty("totalPopulation") + @NotNull + private Long totalPopulation = null; + + @JsonProperty("populationByDemographics") + @Valid + private List populationByDemographics = null; + + @JsonProperty("additionalFields") + @Valid + private List additionalFields = null; + + @JsonProperty("effectiveFrom") + private Long effectiveFrom = null; + + @JsonProperty("effectiveTo") + private Long effectiveTo = null; + + @JsonProperty("source") + @NotNull + private String source = null; + + @JsonIgnore + private List boundaryAncestralPath = null; + + @JsonIgnore + @Builder.Default + private Boolean partnerAssignmentValidationEnabled = Boolean.TRUE; + + @JsonProperty("facilityAssigned") + private Boolean facilityAssigned = null; + + @JsonProperty("workflow") + @Valid + private Workflow workflow; + + @JsonIgnore + private List assigneeJurisdiction; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("auditDetails") + private @Valid AuditDetails auditDetails; + + /** + * Gets or Sets type + */ + public enum TypeEnum { + PEOPLE("people"), + ANIMALS("animals"), + PLANTS("plants"), + OTHER("other"); + + private String value; + + TypeEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static TypeEnum fromValue(String text) { + for (TypeEnum b : TypeEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/census/CensusResponse.java b/health-services/plan-service/src/main/java/digit/web/models/census/CensusResponse.java new file mode 100644 index 00000000000..dabc56422b6 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/census/CensusResponse.java @@ -0,0 +1,42 @@ +package digit.web.models.census; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; +import java.util.Map; + +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * CensusResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Census") + @Valid + private List census = null; + + @JsonProperty("TotalCount") + @Valid + private Integer totalCount = null; + + @JsonProperty("StatusCount") + @Valid + private Map statusCount = null; + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/census/CensusSearchCriteria.java b/health-services/plan-service/src/main/java/digit/web/models/census/CensusSearchCriteria.java new file mode 100644 index 00000000000..4a5a1414d19 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/census/CensusSearchCriteria.java @@ -0,0 +1,72 @@ +package digit.web.models.census; + + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.springframework.validation.annotation.Validated; +import jakarta.validation.constraints.*; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * CensusSearchCriteria + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusSearchCriteria { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("ids") + private Set ids = null; + + @JsonProperty("tenantId") + @Size(min = 1, max = 100) + private String tenantId = null; + + @JsonProperty("areaCodes") + private List areaCodes = null; + + @JsonProperty("status") + private String status = null; + + @JsonProperty("assignee") + private String assignee = null; + + @JsonProperty("source") + private String source = null; + + @JsonProperty("facilityAssigned") + private Boolean facilityAssigned = null; + + @JsonProperty("jurisdiction") + private List jurisdiction = null; + + @JsonProperty("effectiveTo") + private Long effectiveTo = null; + + @JsonProperty("limit") + private Integer limit = null; + + @JsonProperty("offset") + private Integer offset = null; + + public CensusSearchCriteria addAreaCodesItem(String areaCodesItem) { + if (this.areaCodes == null) { + this.areaCodes = new ArrayList<>(); + } + this.areaCodes.add(areaCodesItem); + return this; + } + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/census/CensusSearchRequest.java b/health-services/plan-service/src/main/java/digit/web/models/census/CensusSearchRequest.java new file mode 100644 index 00000000000..157cf16870f --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/census/CensusSearchRequest.java @@ -0,0 +1,31 @@ +package digit.web.models.census; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * CensusSearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusSearchRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("CensusSearchCriteria") + @Valid + private CensusSearchCriteria censusSearchCriteria = null; + + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/census/PopulationByDemographic.java b/health-services/plan-service/src/main/java/digit/web/models/census/PopulationByDemographic.java new file mode 100644 index 00000000000..b36d25b21de --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/census/PopulationByDemographic.java @@ -0,0 +1,69 @@ +package digit.web.models.census; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import jakarta.validation.constraints.Size; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * PopulationByDemographic + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PopulationByDemographic { + + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("demographicVariable") + private DemographicVariableEnum demographicVariable = null; + + @JsonProperty("populationDistribution") + private Object populationDistribution = null; + + /** + * Gets or Sets demographicVariable + */ + public enum DemographicVariableEnum { + AGE("age"), + + GENDER("gender"), + + ETHNICITY("ethnicity"); + + private String value; + + DemographicVariableEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static DemographicVariableEnum fromValue(String text) { + for (DemographicVariableEnum b : DemographicVariableEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/facility/AdditionalFields.java b/health-services/plan-service/src/main/java/digit/web/models/facility/AdditionalFields.java new file mode 100644 index 00000000000..e3b7f19cd31 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/facility/AdditionalFields.java @@ -0,0 +1,25 @@ +package digit.web.models.facility; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AdditionalFields { + + @JsonProperty("schema") + private String schema; + + @JsonProperty("version") + private int version; + + @JsonProperty("fields") + private List fields; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/facility/Address.java b/health-services/plan-service/src/main/java/digit/web/models/facility/Address.java new file mode 100644 index 00000000000..f6a5e2c8c0b --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/facility/Address.java @@ -0,0 +1,62 @@ +package digit.web.models.facility; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Address { + + @JsonProperty("id") + private String id; + + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("clientReferenceId") + private String clientReferenceId; + + @JsonProperty("doorNo") + private String doorNo; + + @JsonProperty("latitude") + private Double latitude; + + @JsonProperty("longitude") + private Double longitude; + + @JsonProperty("locationAccuracy") + private Double locationAccuracy; + + @JsonProperty("type") + private String type; + + @JsonProperty("addressLine1") + private String addressLine1; + + @JsonProperty("addressLine2") + private String addressLine2; + + @JsonProperty("landmark") + private String landmark; + + @JsonProperty("city") + private String city; + + @JsonProperty("pincode") + private String pincode; + + @JsonProperty("buildingName") + private String buildingName; + + @JsonProperty("street") + private String street; + + @JsonProperty("locality") + private Locality locality; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/facility/Facility.java b/health-services/plan-service/src/main/java/digit/web/models/facility/Facility.java new file mode 100644 index 00000000000..fcfec9b1ee9 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/facility/Facility.java @@ -0,0 +1,64 @@ +package digit.web.models.facility; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; + +import java.util.Map; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Facility { + @JsonProperty("id") + private String id; + + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("source") + private String source; + + @JsonProperty("rowVersion") + private Integer rowVersion; + + @JsonProperty("applicationId") + private String applicationId; + + @JsonProperty("hasErrors") + private boolean hasErrors; + + @JsonProperty("additionalFields") + private AdditionalFields additionalFields; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails; + + @JsonProperty("clientReferenceId") + private String clientReferenceId; + + @JsonProperty("clientAuditDetails") + private String clientAuditDetails; + + @JsonProperty("isPermanent") + private boolean isPermanent; + + @JsonProperty("name") + private String name; + + @JsonProperty("usage") + private String usage; + + @JsonProperty("storageCapacity") + private Integer storageCapacity; + + @JsonProperty("address") + private Address address; + + @JsonProperty("isDeleted") + private boolean isDeleted; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/facility/FacilityDetail.java b/health-services/plan-service/src/main/java/digit/web/models/facility/FacilityDetail.java new file mode 100644 index 00000000000..9f09df28102 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/facility/FacilityDetail.java @@ -0,0 +1,19 @@ +package digit.web.models.facility; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FacilityDetail { + @JsonProperty("facility") + private Facility facility; + + @JsonProperty("additionalInfo") + private String additionalInfo; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/facility/FacilityResponse.java b/health-services/plan-service/src/main/java/digit/web/models/facility/FacilityResponse.java new file mode 100644 index 00000000000..46e98759e48 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/facility/FacilityResponse.java @@ -0,0 +1,22 @@ +package digit.web.models.facility; + +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 java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FacilityResponse { + @JsonProperty("ResponseInfo") + private ResponseInfo responseInfo; + + @JsonProperty("Facilities") + private List facilities; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/facility/FacilitySearchCriteria.java b/health-services/plan-service/src/main/java/digit/web/models/facility/FacilitySearchCriteria.java new file mode 100644 index 00000000000..ae76b88fa4a --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/facility/FacilitySearchCriteria.java @@ -0,0 +1,30 @@ +package digit.web.models.facility; + +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.web.models.Pagination; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FacilitySearchCriteria { + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("id") + private List id; + + @JsonProperty("name") + private String name; + + @JsonProperty("isDeleted") + private Boolean isDeleted; + + @JsonProperty("pagination") + private Pagination pagination; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/facility/FacilitySearchRequest.java b/health-services/plan-service/src/main/java/digit/web/models/facility/FacilitySearchRequest.java new file mode 100644 index 00000000000..c7d39e4053e --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/facility/FacilitySearchRequest.java @@ -0,0 +1,20 @@ +package digit.web.models.facility; + +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 +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FacilitySearchRequest { + @JsonProperty("RequestInfo") + private RequestInfo requestInfo; + + @JsonProperty("Facility") + private FacilitySearchCriteria facilitySearchCriteria; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/facility/Field.java b/health-services/plan-service/src/main/java/digit/web/models/facility/Field.java new file mode 100644 index 00000000000..3cbd343bf76 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/facility/Field.java @@ -0,0 +1,20 @@ +package digit.web.models.facility; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Field { + + @JsonProperty("key") + private String key; + + @JsonProperty("value") + private String value; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/facility/Locality.java b/health-services/plan-service/src/main/java/digit/web/models/facility/Locality.java new file mode 100644 index 00000000000..68552c0898a --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/facility/Locality.java @@ -0,0 +1,33 @@ +package digit.web.models.facility; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Locality { + + @JsonProperty("id") + private String id; + + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("code") + private String code; + + @JsonProperty("geometry") + private String geometry; // Assuming geometry is a string, adjust based on your actual data + + @JsonProperty("auditDetails") + private AuditDetails auditDetails; + + @JsonProperty("additionalDetails") + private String additionalDetails; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/Mdms.java b/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/Mdms.java new file mode 100644 index 00000000000..be5e324cd5f --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/Mdms.java @@ -0,0 +1,55 @@ +package digit.web.models.mdmsV2; + +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.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/** + * Mdms + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Mdms { + + @JsonProperty("id") + @Size(min = 2, max = 64) + private String id; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 128) + private String tenantId = null; + + @JsonProperty("schemaCode") + @NotNull + @Size(min = 2, max = 128) + private String schemaCode = null; + + @JsonProperty("uniqueIdentifier") + @Size(min = 2, max = 128) + private String uniqueIdentifier = null; + + @JsonProperty("data") + @NotNull + private JsonNode data = null; + + @JsonProperty("isActive") + private Boolean isActive = true; + + @JsonProperty("auditDetails") + @Valid + private AuditDetails auditDetails = null; + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsCriteriaReqV2.java b/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsCriteriaReqV2.java new file mode 100644 index 00000000000..f6af90e1b82 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsCriteriaReqV2.java @@ -0,0 +1,23 @@ +package digit.web.models.mdmsV2; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; +import org.egov.common.contract.request.RequestInfo; + +import javax.validation.Valid; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class MdmsCriteriaReqV2 { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo; + + @JsonProperty("MdmsCriteria") + @Valid + private MdmsCriteriaV2 mdmsCriteriaV2; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsCriteriaV2.java b/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsCriteriaV2.java new file mode 100644 index 00000000000..88e8a715810 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsCriteriaV2.java @@ -0,0 +1,62 @@ +package digit.web.models.mdmsV2; + +import com.fasterxml.jackson.annotation.JsonIgnore; +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; +import javax.validation.constraints.Size; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Data +@Validated +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class MdmsCriteriaV2 { + + @JsonProperty("tenantId") + @Size(min = 1, max = 100) + @NotNull + private String tenantId; + + @JsonProperty("ids") + private Set ids; + + @JsonProperty("uniqueIdentifier") + @Size(min = 1, max = 64) + private String uniqueIdentifier; + + @JsonProperty("uniqueIdentifiers") + private List uniqueIdentifiers; + + @JsonProperty("schemaCode") + private String schemaCode; + + @JsonProperty("filters") + private Map filterMap; + + @JsonProperty("isActive") + private Boolean isActive; + + @JsonIgnore + private Map schemaCodeFilterMap; + + @JsonIgnore + private Set uniqueIdentifiersForRefVerification; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsResponseV2.java b/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsResponseV2.java new file mode 100644 index 00000000000..090b41f90da --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/mdmsV2/MdmsResponseV2.java @@ -0,0 +1,25 @@ +package digit.web.models.mdmsV2; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; +import org.egov.common.contract.response.ResponseInfo; + +import javax.validation.Valid; +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) + +public class MdmsResponseV2 { + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("mdms") + @Valid + private List mdms = null; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Boundary.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Boundary.java new file mode 100644 index 00000000000..a1b725cbd6f --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Boundary.java @@ -0,0 +1,32 @@ +package digit.web.models.projectFactory; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Boundary + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Boundary { + + @JsonProperty("code") + private String code; + + @JsonProperty("type") + private String type; + + @JsonProperty("isRoot") + private Boolean isRoot; + + @JsonProperty("includeAllChildren") + private Boolean includeAllChildren; + + @JsonProperty("parent") + private String parent; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignDetail.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignDetail.java new file mode 100644 index 00000000000..ee9d064547a --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignDetail.java @@ -0,0 +1,85 @@ +package digit.web.models.projectFactory; + +import jakarta.validation.Valid; +import jakarta.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.models.AuditDetails; + +import java.util.List; + +/** + * CampaignDetails + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CampaignDetail { + + @JsonProperty("id") + private String id; + + @JsonProperty("tenantId") + @NotNull + private String tenantId; + + @JsonProperty("status") + private String status; + + @JsonProperty("action") + private String action; + + @JsonProperty("campaignNumber") + private String campaignNumber; + + @JsonProperty("isActive") + private Boolean isActive; + + @JsonProperty("parentId") + private String parentId; + + @JsonProperty("campaignName") + private String campaignName; + + @JsonProperty("projectType") + private String projectType; + + @JsonProperty("hierarchyType") + private String hierarchyType; + + @JsonProperty("boundaryCode") + private String boundaryCode; + + @JsonProperty("projectId") + private String projectId; + + @JsonProperty("startDate") + private Long startDate; + + @JsonProperty("endDate") + private Long endDate; + + @JsonProperty("additionalDetails") + @Valid + private Object additionalDetails; + + @JsonProperty("resources") + @Valid + private List resources; + + @JsonProperty("boundaries") + @Valid + private List boundaries; + + @JsonProperty("deliveryRules") + @Valid + private List deliveryRules; + + @JsonProperty("auditDetails") + @Valid + private AuditDetails auditDetails; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignResponse.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignResponse.java new file mode 100644 index 00000000000..e03e4bb01c7 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignResponse.java @@ -0,0 +1,29 @@ +package digit.web.models.projectFactory; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.*; +import org.egov.common.contract.response.ResponseInfo; + +import java.util.List; + +/** + * CampaignResponse + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CampaignResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("CampaignDetails") + @Valid + private List campaignDetails = null; + + @JsonProperty("totalCount") + @Valid + private Integer totalCount = null; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignSearchCriteria.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignSearchCriteria.java new file mode 100644 index 00000000000..36ef6675594 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignSearchCriteria.java @@ -0,0 +1,51 @@ +package digit.web.models.projectFactory; + +import com.fasterxml.jackson.annotation.JsonIgnore; +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; + +import java.util.List; + +/** + * CampaignSearchCriteria + */ +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +@Validated +public class CampaignSearchCriteria { + + @JsonProperty("ids") + @Size(min = 1) + private List ids; + + @JsonProperty("tenantId") + @Size(min = 2, max = 256) + private String tenantId; + + @JsonIgnore + private List status; + + @JsonIgnore + private String createdBy; + + @JsonIgnore + private Boolean campaignsIncludeDates; + + @JsonIgnore + private Integer startDate; + + @JsonIgnore + private Integer endDate; + + @JsonProperty("pagination") + @Valid + private Pagination pagination; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignSearchReq.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignSearchReq.java new file mode 100644 index 00000000000..391420396ed --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/CampaignSearchReq.java @@ -0,0 +1,22 @@ +package digit.web.models.projectFactory; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.Builder; +import lombok.Data; +import org.egov.common.contract.request.RequestInfo; + +/** + * CampaignSearchReq + */ +@Data +@Builder +public class CampaignSearchReq { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo; + + @JsonProperty("CampaignDetails") + private CampaignSearchCriteria campaignSearchCriteria; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Condition.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Condition.java new file mode 100644 index 00000000000..5ad19e29aef --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Condition.java @@ -0,0 +1,27 @@ +package digit.web.models.projectFactory; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Condition + **/ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Condition { + + @JsonProperty("value") + private String value; + + @JsonProperty("operator") + private String operator; + + @JsonProperty("attribute") + private String attribute; +} + diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/DeliveryRule.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/DeliveryRule.java new file mode 100644 index 00000000000..7eef58fd8ae --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/DeliveryRule.java @@ -0,0 +1,43 @@ +package digit.web.models.projectFactory; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * DeliveryRule + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DeliveryRule { + + @JsonProperty("endDate") + private Long endDate; + + @JsonProperty("products") + @Valid + private List products; + + @JsonProperty("startDate") + private Long startDate; + + @JsonProperty("conditions") + @Valid + private List conditions; + + @JsonProperty("cycleNumber") + private Integer cycleNumber; + + @JsonProperty("deliveryNumber") + private Integer deliveryNumber; + + @JsonProperty("deliveryRuleNumber") + private Integer deliveryRuleNumber; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Pagination.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Pagination.java new file mode 100644 index 00000000000..7e8d28c30ce --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Pagination.java @@ -0,0 +1,35 @@ +package digit.web.models.projectFactory; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Pagination + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Pagination { + + @JsonIgnore + private String sortBy; + + @JsonIgnore + private String sortOrder; + + @JsonProperty("limit") + @Min(1) + @Max(50) + private Integer limit; + + @JsonProperty("offset") + @Min(0) + private Integer offset; +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Product.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Product.java new file mode 100644 index 00000000000..9c4e560cc7f --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Product.java @@ -0,0 +1,26 @@ +package digit.web.models.projectFactory; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Product + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Product { + + @JsonProperty("name") + private String name; + + @JsonProperty("count") + private Integer count; + + @JsonProperty("value") + private String value; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Resource.java b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Resource.java new file mode 100644 index 00000000000..07f04a281bb --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/projectFactory/Resource.java @@ -0,0 +1,32 @@ +package digit.web.models.projectFactory; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Resource + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Resource { + + @JsonProperty("type") + private String type; + + @JsonProperty("filename") + private String filename; + + @JsonProperty("resourceId") + private String resourceId; + + @JsonProperty("filestoreId") + private String filestoreId; + + @JsonProperty("createResourceId") + private String createResourceId; +} \ No newline at end of file diff --git a/health-services/plan-service/src/main/resources/application.properties b/health-services/plan-service/src/main/resources/application.properties index 03ee3da916d..cb941721390 100644 --- a/health-services/plan-service/src/main/resources/application.properties +++ b/health-services/plan-service/src/main/resources/application.properties @@ -30,6 +30,7 @@ spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.Strin 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 +spring.kafka.producer.properties.max.request.size=3000000 # KAFKA CONSUMER CONFIGURATIONS kafka.consumer.config.auto_commit=true @@ -48,14 +49,57 @@ plan.configuration.update.topic=plan-config-update-topic plan.create.topic=save-plan plan.update.topic=update-plan +plan.bulk.update.topic=bulk-update-plan -#mdms urls +plan.facility.update.topic=update-plan-facility +plan.facility.create.topic=save-plan-facility + +plan.employee.assignment.create.topic=plan-employee-assignment-create-topic +plan.employee.assignment.update.topic=plan-employee-assignment-update-topic + +# Census +egov.census.host=https://unified-dev.digit.org +egov.census.search.endpoint=/census-service/_search + +# Facility +egov.facility.host=https://unified-dev.digit.org +egov.facility.search.endpoint=/facility/v1/_search + +# MDMS urls egov.mdms.host=https://unified-dev.digit.org -egov.mdms.search.endpoint=/egov-mdms-service/v1/_search +egov.mdms.search.endpoint=/mdms-v2/v1/_search +egov.mdms.search.v2.endpoint=/mdms-v2/v2/_search + +# Project factory urls +egov.project.factory.host=https://unified-dev.digit.org +egov.project.factory.search.endpoint=/project-factory/v1/project-type/search + +#User Service +egov.user.service.host=https://unified-dev.digit.org +egov.user.search.endpoint=/user/_search + +#Boundary service urls +egov.boundary.service.host=https://unified-dev.digit.org +egov.boundary.relationship.search.endpoint=/boundary-service/boundary-relationships/_search +egov.boundary.hierarchy.search.endpoint=/boundary-service/boundary-hierarchy-definition/_search + +# Workflow +egov.workflow.host=https://unified-dev.digit.org +egov.workflow.transition.path=/egov-workflow-v2/egov-wf/process/_transition +egov.business.service.search.endpoint=/egov-workflow-v2/egov-wf/businessservice/_search +workflow.initiate.action=INITIATE +workflow.intermediate.action=EDIT_AND_SEND_FOR_APPROVAL,APPROVE +workflow.send.back.actions=SEND_BACK_FOR_CORRECTION # Pagination config plan.default.offset=0 plan.default.limit=10 +# CONSUMER TOPICS resource.config.consumer.plan.create.topic=resource-microplan-create-topic -resource.update.plan.config.consumer.topic=resource-plan-config-update-topic \ No newline at end of file +resource.update.plan.config.consumer.topic=resource-plan-config-update-topic +project.factory.save.plan.facility.consumer.topic=project-factory-save-plan-facility + +# Role Map +plan.estimation.approver.roles = ROOT_PLAN_ESTIMATION_APPROVER, PLAN_ESTIMATION_APPROVER +role.map = {'ROOT_FACILITY_CATCHMENT_MAPPER':'FACILITY_CATCHMENT_MAPPER', 'FACILITY_CATCHMENT_MAPPER':'ROOT_FACILITY_CATCHMENT_MAPPER', 'ROOT_POPULATION_DATA_APPROVER':'POPULATION_DATA_APPROVER', 'POPULATION_DATA_APPROVER':'ROOT_POPULATION_DATA_APPROVER', 'ROOT_PLAN_ESTIMATION_APPROVER':'PLAN_ESTIMATION_APPROVER', 'PLAN_ESTIMATION_APPROVER':'ROOT_PLAN_ESTIMATION_APPROVER'} diff --git a/health-services/plan-service/src/main/resources/db/Dockerfile b/health-services/plan-service/src/main/resources/db/Dockerfile index 60fc07ce69f..f38638a269f 100644 --- a/health-services/plan-service/src/main/resources/db/Dockerfile +++ b/health-services/plan-service/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"] diff --git a/health-services/plan-service/src/main/resources/db/migrate.sh b/health-services/plan-service/src/main/resources/db/migrate.sh index 43960b25cdb..f9d6617822c 100644 --- a/health-services/plan-service/src/main/resources/db/migrate.sh +++ b/health-services/plan-service/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 diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20240305113045__plan_configuration_create_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20240305113045__plan_configuration_create_ddl.sql index e9630421bcb..fa1cc87dc6a 100644 --- a/health-services/plan-service/src/main/resources/db/migration/main/V20240305113045__plan_configuration_create_ddl.sql +++ b/health-services/plan-service/src/main/resources/db/migration/main/V20240305113045__plan_configuration_create_ddl.sql @@ -1,9 +1,11 @@ -- Table: plan_configuration CREATE TABLE plan_configuration ( id character varying(64), - tenant_id character varying(64), - name character varying(128), - execution_plan_id character varying(64), + tenant_id character varying(64) not null, + name character varying(128) not null, + campaign_id character varying(64) not null, + status character varying(64) not null, + additional_details JSONB, created_by character varying(64), created_time bigint, last_modified_by character varying(64), @@ -16,8 +18,10 @@ CREATE TABLE plan_configuration ( CREATE TABLE plan_configuration_files ( id character varying(64), plan_configuration_id character varying(64), - filestore_id character varying(128), - input_file_type character varying(64), + filestore_id character varying(128) not null, + input_file_type character varying(64) not null, + template_identifier character varying(128) not null, + active boolean not null, created_by character varying(64), created_time bigint, last_modified_by character varying(64), @@ -30,9 +34,12 @@ CREATE TABLE plan_configuration_files ( -- Table: plan_configuration_assumptions CREATE TABLE plan_configuration_assumptions ( id character varying(64), - key character varying(256), - value numeric(12,2), + key character varying(256) not null, + value numeric(12,2) not null, + source character varying(64), + category character varying(64), plan_configuration_id character varying(64), + active boolean not null, created_by character varying(64), created_time bigint, last_modified_by character varying(64), @@ -45,10 +52,15 @@ CREATE TABLE plan_configuration_assumptions ( -- Table: plan_configuration_operations CREATE TABLE plan_configuration_operations ( id character varying(64), - input character varying(256), - operator character varying(64), - assumption_value character varying(256), - output character varying(64), + input character varying(256) not null, + operator character varying(64) not null, + assumption_value character varying(256) not null, + output character varying(256) not null, + show_on_estimation_dashboard boolean, + source character varying(64), + category character varying(64), + active boolean not null, + execution_order numeric(12,2), plan_configuration_id character varying(64), created_by character varying(64), created_time bigint, @@ -62,8 +74,10 @@ CREATE TABLE plan_configuration_operations ( -- Table: plan_configuration_mapping CREATE TABLE plan_configuration_mapping ( id character varying(64), - mapped_from character varying(256), - mapped_to character varying(256), + mapped_from character varying(256) not null, + mapped_to character varying(256) not null, + filestore_id character varying(128) not null, + active boolean not null, plan_configuration_id character varying(64), created_by character varying(64), created_time bigint, diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20240305113047__plan_create_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20240305113047__plan_create_ddl.sql index 942cc36af38..b8a194f4afa 100644 --- a/health-services/plan-service/src/main/resources/db/migration/main/V20240305113047__plan_create_ddl.sql +++ b/health-services/plan-service/src/main/resources/db/migration/main/V20240305113047__plan_create_ddl.sql @@ -2,7 +2,10 @@ CREATE TABLE plan ( id varchar(64), tenant_id varchar(64), locality varchar(64), - execution_plan_id varchar(64), + campaign_id varchar(64), + status character varying(64) not null, + assignee varchar(64), + boundary_ancestral_path TEXT, plan_configuration_id varchar(64), additional_details JSONB, created_by varchar(64), diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20240404113045__plan_configuration_add_filestoreid_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20240404113045__plan_configuration_add_filestoreid_ddl.sql deleted file mode 100644 index fcd7cfe2bbc..00000000000 --- a/health-services/plan-service/src/main/resources/db/migration/main/V20240404113045__plan_configuration_add_filestoreid_ddl.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE plan_configuration_mapping ADD filestore_id character varying(128); diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20240404150000__plan_configuration_add_template_identifier_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20240404150000__plan_configuration_add_template_identifier_ddl.sql deleted file mode 100644 index e1c67ff2696..00000000000 --- a/health-services/plan-service/src/main/resources/db/migration/main/V20240404150000__plan_configuration_add_template_identifier_ddl.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE plan_configuration_files ADD template_identifier character varying(128); diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20240923113045__plan_facility_create_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20240923113045__plan_facility_create_ddl.sql new file mode 100644 index 00000000000..0f037765d8f --- /dev/null +++ b/health-services/plan-service/src/main/resources/db/migration/main/V20240923113045__plan_facility_create_ddl.sql @@ -0,0 +1,19 @@ +-- Table: plan_facility_linkage +CREATE TABLE plan_facility_linkage ( + id varchar(64), + tenant_id varchar(64), + plan_configuration_id varchar(64), + facility_id varchar(64), + residing_boundary varchar(64), + service_boundaries TEXT, + additional_details JSONB, + plan_configuration_name character varying(128), + facility_name character varying(64), + active boolean, + created_by varchar(64), + created_time bigint, + last_modified_by varchar(64), + last_modified_time bigint, + CONSTRAINT uk_plan_facility_linkage_id PRIMARY KEY (id), + FOREIGN KEY (plan_configuration_id) REFERENCES plan_configuration(id) +); \ No newline at end of file diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20241604150000__plan_configuration_add_status_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20241604150000__plan_configuration_add_status_ddl.sql deleted file mode 100644 index 8683e34faef..00000000000 --- a/health-services/plan-service/src/main/resources/db/migration/main/V20241604150000__plan_configuration_add_status_ddl.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE plan_configuration ADD status character varying(64); -UPDATE plan_configuration SET status = 'DRAFT' WHERE status IS NULL; diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20242105150000__plan_configuration_add_active_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20242105150000__plan_configuration_add_active_ddl.sql deleted file mode 100644 index 3586cd4cb45..00000000000 --- a/health-services/plan-service/src/main/resources/db/migration/main/V20242105150000__plan_configuration_add_active_ddl.sql +++ /dev/null @@ -1,11 +0,0 @@ -ALTER TABLE plan_configuration_files ADD active boolean; -UPDATE plan_configuration_files SET active = true WHERE active IS NULL; - -ALTER TABLE plan_configuration_assumptions ADD active boolean; -UPDATE plan_configuration_assumptions SET active = true WHERE active IS NULL; - -ALTER TABLE plan_configuration_operations ADD active boolean; -UPDATE plan_configuration_operations SET active = true WHERE active IS NULL; - -ALTER TABLE plan_configuration_mapping ADD active boolean; -UPDATE plan_configuration_mapping SET active = true WHERE active IS NULL; \ No newline at end of file diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20242109141800__plan_employee_assignment_create_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20242109141800__plan_employee_assignment_create_ddl.sql new file mode 100644 index 00000000000..1e28950ca6f --- /dev/null +++ b/health-services/plan-service/src/main/resources/db/migration/main/V20242109141800__plan_employee_assignment_create_ddl.sql @@ -0,0 +1,19 @@ +-- Table: plan_employee_assignment +CREATE TABLE plan_employee_assignment ( + id character varying(64), + tenant_id character varying(64), + plan_configuration_id character varying(64), + employee_id character varying(64), + role character varying(64), + hierarchy_level character varying(64), + jurisdiction TEXT, + plan_configuration_name character varying(128), + additional_details JSONB, + active boolean DEFAULT true, + created_by character varying(64), + created_time bigint, + last_modified_by character varying(64), + last_modified_time bigint, + CONSTRAINT uk_plan_employee_assignment_id PRIMARY KEY (id), + FOREIGN KEY (plan_configuration_id) REFERENCES plan_configuration(id) +); diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20242110115700__alter_plan_assignee_create_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20242110115700__alter_plan_assignee_create_ddl.sql new file mode 100644 index 00000000000..584399af592 --- /dev/null +++ b/health-services/plan-service/src/main/resources/db/migration/main/V20242110115700__alter_plan_assignee_create_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE plan ALTER COLUMN assignee TYPE TEXT; diff --git a/health-services/plan-service/src/main/resources/db/migration/main/V20242112141500__alter plan_facility_add_boundary_ancestral_path_ddl.sql b/health-services/plan-service/src/main/resources/db/migration/main/V20242112141500__alter plan_facility_add_boundary_ancestral_path_ddl.sql new file mode 100644 index 00000000000..0bf373ddcd7 --- /dev/null +++ b/health-services/plan-service/src/main/resources/db/migration/main/V20242112141500__alter plan_facility_add_boundary_ancestral_path_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE plan_facility_linkage ADD boundary_ancestral_path TEXT; \ No newline at end of file diff --git a/health-services/project-factory/CHANGELOG.md b/health-services/project-factory/CHANGELOG.md index 55f990d91ba..47034044d78 100644 --- a/health-services/project-factory/CHANGELOG.md +++ b/health-services/project-factory/CHANGELOG.md @@ -8,3 +8,15 @@ 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. + +## 0.3.0 - 2024-12-03 + 1. Campaign Details Table Updates -> added new columns: parentId and active,removed unique constraint on campaignName. + 2. Update Ongoing Campaign (can add new boundaries , edit facilities , user and target sheet). + 3. Boundary Management Apis added. + 4. Microplan Integration api (fetch-from-microplan api) added. diff --git a/health-services/project-factory/Dockerfile b/health-services/project-factory/Dockerfile index 124ed02c197..4b942010773 100644 --- a/health-services/project-factory/Dockerfile +++ b/health-services/project-factory/Dockerfile @@ -13,6 +13,7 @@ ARG COMMIT_ID ENV BRANCH_NAME=$BRANCH_NAME ENV ACTION_NUMBER=$ACTION_NUMBER ENV COMMIT_ID=$COMMIT_ID +ENV NODE_OPTIONS="--max-old-space-size=2048" # Copy package.json and yarn.lock (if exists) COPY package.json ./ @@ -30,5 +31,4 @@ COPY . . EXPOSE 3000 CMD ["yarn", "prod"] - # Replace "app.js" with your entry point file - +# Replaced by CMD ["yarn", "prod"] \ No newline at end of file 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/V20240315110400__resource_details_ddl.sql b/health-services/project-factory/migration/main/V20240315110400__resource_details_ddl.sql deleted file mode 100644 index aecfae20001..00000000000 --- a/health-services/project-factory/migration/main/V20240315110400__resource_details_ddl.sql +++ /dev/null @@ -1,46 +0,0 @@ -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/main/V20240315110513__campaign_details_ddl.sql b/health-services/project-factory/migration/main/V20240315110513__campaign_details_ddl.sql deleted file mode 100644 index 1f6426149f5..00000000000 --- a/health-services/project-factory/migration/main/V20240315110513__campaign_details_ddl.sql +++ /dev/null @@ -1,16 +0,0 @@ -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/main/V20240401154500__campaign_details_add_columns.sql b/health-services/project-factory/migration/main/V20240401154500__campaign_details_add_columns.sql deleted file mode 100644 index eaf0c681333..00000000000 --- a/health-services/project-factory/migration/main/V20240401154500__campaign_details_add_columns.sql +++ /dev/null @@ -1,3 +0,0 @@ -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/main/V20240402134500__campaign_details_alter_column.sql b/health-services/project-factory/migration/main/V20240402134500__campaign_details_alter_column.sql deleted file mode 100644 index 7a49127c9dd..00000000000 --- a/health-services/project-factory/migration/main/V20240402134500__campaign_details_alter_column.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE eg_cm_campaign_details -ALTER COLUMN hierarchyType DROP NOT NULL; diff --git a/health-services/project-factory/migration/main/V20240410154500__campaign_details_alter_column.sql b/health-services/project-factory/migration/main/V20240410154500__campaign_details_alter_column.sql deleted file mode 100644 index 05dfea2b5c7..00000000000 --- a/health-services/project-factory/migration/main/V20240410154500__campaign_details_alter_column.sql +++ /dev/null @@ -1,3 +0,0 @@ -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/main/V20240416170000__generate_add_column.sql b/health-services/project-factory/migration/main/V20240416170000__generate_add_column.sql deleted file mode 100644 index c96caaa0e5f..00000000000 --- a/health-services/project-factory/migration/main/V20240416170000__generate_add_column.sql +++ /dev/null @@ -1,2 +0,0 @@ -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/main/V20240427174100__campaign_add_column.sql b/health-services/project-factory/migration/main/V20240427174100__campaign_add_column.sql deleted file mode 100644 index 36707083732..00000000000 --- a/health-services/project-factory/migration/main/V20240427174100__campaign_add_column.sql +++ /dev/null @@ -1,2 +0,0 @@ -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/main/V20240522143500__resource_details_alter_column.sql b/health-services/project-factory/migration/main/V20240522143500__resource_details_alter_column.sql deleted file mode 100644 index 25fc10438f1..00000000000 --- a/health-services/project-factory/migration/main/V20240522143500__resource_details_alter_column.sql +++ /dev/null @@ -1,2 +0,0 @@ -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/main/V20240826145500__add_resource_and_campaign.sql b/health-services/project-factory/migration/main/V20240826145500__add_resource_and_campaign.sql new file mode 100644 index 00000000000..09165a225d3 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240826145500__add_resource_and_campaign.sql @@ -0,0 +1,92 @@ +CREATE TABLE eg_cm_campaign_details +( + id character varying(128) NOT NULL, + 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), + 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, + campaignname character varying(250), + projecttype character varying(128), + startdate bigint, + enddate bigint, + CONSTRAINT eg_cm_campaign_details_pkey PRIMARY KEY (id), + CONSTRAINT eg_cm_campaign_details_campaignname_key UNIQUE (campaignname) +); + +CREATE TABLE eg_cm_campaign_process +( + id character varying(128) NOT NULL, + campaignid character varying(128) NOT NULL, + type character varying(128), + status character varying(128), + details jsonb, + createdtime bigint, + lastmodifiedtime bigint, + additionaldetails jsonb, + CONSTRAINT eg_cm_campaign_process_pkey PRIMARY KEY (id), + CONSTRAINT uq_campaignid_type UNIQUE (campaignid, type) +); + +CREATE TABLE eg_cm_generated_resource_details +( + id character varying(128) NOT NULL, + filestoreid character varying(128), + status character varying(128), + type character varying(128), + tenantid character varying(128), + count bigint, + createdby character varying(128), + createdtime bigint, + lastmodifiedby character varying(128), + lastmodifiedtime bigint, + additionaldetails jsonb, + hierarchytype character varying(128), + campaignid character varying(128), + CONSTRAINT eg_cm_generated_resource_details_pkey PRIMARY KEY (id) +); + +CREATE TABLE eg_cm_resource_activity +( + id character varying(128) NOT NULL, + retrycount integer, + type character varying(64), + url character varying(128), + requestpayload jsonb, + tenantid character varying(128) NOT NULL, + responsepayload jsonb, + status bigint, + createdby character varying(128), + createdtime bigint, + lastmodifiedby character varying(128), + lastmodifiedtime bigint, + additionaldetails jsonb, + resourcedetailsid character varying(128), + CONSTRAINT eg_cm_resource_activity_pkey PRIMARY KEY (id) +); + +CREATE TABLE eg_cm_resource_details +( + id character varying(128) NOT NULL, + status character varying(128) NOT NULL, + tenantid character varying(128) NOT NULL, + filestoreid character varying(128) NOT NULL, + processedfilestoreid character varying(128), + action character varying(128) NOT NULL, + type character varying(64) NOT NULL, + createdby character varying(128) NOT NULL, + createdtime bigint NOT NULL, + lastmodifiedby character varying(128), + lastmodifiedtime bigint, + additionaldetails jsonb, + campaignid character varying(128), + CONSTRAINT eg_cm_resource_details_pkey PRIMARY KEY (id) +); \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240829125000__add_index_on_tables.sql b/health-services/project-factory/migration/main/V20240829125000__add_index_on_tables.sql new file mode 100644 index 00000000000..59df89af11c --- /dev/null +++ b/health-services/project-factory/migration/main/V20240829125000__add_index_on_tables.sql @@ -0,0 +1,5 @@ +CREATE INDEX idx_eg_cm_campaign_details_status ON eg_cm_campaign_details(status); +CREATE INDEX idx_eg_cm_campaign_details_campaignname ON eg_cm_campaign_details(campaignname); +CREATE INDEX idx_eg_cm_campaign_process_campaignid ON eg_cm_campaign_process(campaignid); +CREATE INDEX idx_eg_cm_generated_resource_details_campaignid ON eg_cm_generated_resource_details(campaignid); +CREATE INDEX idx_eg_cm_resource_details_campaignid ON eg_cm_resource_details(campaignid); diff --git a/health-services/project-factory/migration/main/V20240902104800__add_parentid_isactive_in_eg_campaign_details.sql b/health-services/project-factory/migration/main/V20240902104800__add_parentid_isactive_in_eg_campaign_details.sql new file mode 100644 index 00000000000..6ce6b0f771e --- /dev/null +++ b/health-services/project-factory/migration/main/V20240902104800__add_parentid_isactive_in_eg_campaign_details.sql @@ -0,0 +1,5 @@ +ALTER TABLE eg_cm_campaign_details +ADD COLUMN parentid character varying(128); + +ALTER TABLE eg_cm_campaign_details +ADD COLUMN isactive boolean; \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240913115000__remove_campaign_name_unique_constraint.sql b/health-services/project-factory/migration/main/V20240913115000__remove_campaign_name_unique_constraint.sql new file mode 100644 index 00000000000..34aa7b31978 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240913115000__remove_campaign_name_unique_constraint.sql @@ -0,0 +1,2 @@ +ALTER TABLE eg_cm_campaign_details +DROP CONSTRAINT eg_cm_campaign_details_campaignname_key; diff --git a/health-services/project-factory/migration/main/V20241013115000__add_hierarchytype_column.sql b/health-services/project-factory/migration/main/V20241013115000__add_hierarchytype_column.sql new file mode 100644 index 00000000000..e44468f1cc5 --- /dev/null +++ b/health-services/project-factory/migration/main/V20241013115000__add_hierarchytype_column.sql @@ -0,0 +1 @@ +ALTER TABLE eg_cm_resource_details ADD COLUMN hierarchytype 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 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..c13d8382b36 100644 --- a/health-services/project-factory/package-lock.json +++ b/health-services/project-factory/package-lock.json @@ -1,23 +1,24 @@ { "name": "project-factory", - "version": "0.0.1", + "version": "0.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "project-factory", - "version": "0.0.1", + "version": "0.2.0", "license": "MIT", "dependencies": { "ajv-errors": "^3.0.0", "axios": "1.6.8", "body-parser": "^1.20.2", "compression": "1.7.4", - "exceljs": "4.4.0", + "exceljs": "^4.4.0", "express": "^4.19.2", "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.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/highlight": "^7.10.4" + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.24.4", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", + "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.4", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", "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", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", "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==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "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.25.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", + "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.24.0", + "@babel/types": "^7.25.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -188,15 +168,14 @@ } }, "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==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-validator-option": "^7.23.5", - "browserslist": "^4.22.2", + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -204,78 +183,53 @@ "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-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-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-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==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.24.0" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "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==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", "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.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" }, "engines": { "node": ">=6.9.0" @@ -285,92 +239,74 @@ } }, "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.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", "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==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "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==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", "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.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "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==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.4", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", + "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0" + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.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==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -384,7 +320,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 +332,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 +346,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 +354,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 +370,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 +378,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.4", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", + "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", "dev": true, - "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.2" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -473,7 +397,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 +409,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 +421,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 +433,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 +445,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" }, @@ -534,13 +453,12 @@ } }, "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==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -554,7 +472,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 +484,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 +496,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 +508,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 +520,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 +532,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 +544,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" }, @@ -644,13 +555,12 @@ } }, "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==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", + "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -660,49 +570,30 @@ } }, "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==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.2", - "picocolors": "^1.0.0" + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.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.25.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz", + "integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==", "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", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.2", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -710,26 +601,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==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -747,7 +623,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 +631,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.25.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", + "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", "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.8", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -778,14 +651,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 +666,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 +678,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 +687,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", @@ -863,9 +731,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -891,6 +759,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 +808,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 +833,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 +840,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 +860,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 +870,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 +891,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 +900,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 +909,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 +926,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 +968,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 +1009,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 +1022,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 +1034,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 +1051,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 +1066,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,12 +1104,32 @@ } } }, + "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, + "engines": { + "node": ">=8" + } + }, + "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, - "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.27.8" }, @@ -1266,7 +1142,6 @@ "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", @@ -1281,7 +1156,6 @@ "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 +1171,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 +1186,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 +1212,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 +1229,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 +1243,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,24 +1252,21 @@ "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" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "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 +1276,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 +1287,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 +1298,21 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/@npmcli/fs/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "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 +1322,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 +1338,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 +1346,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 +1384,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,18 +1393,16 @@ "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==", + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.20.7" } @@ -1558,7 +1412,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 +1422,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 +1431,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 +1440,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 +1448,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.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", + "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -1615,7 +1464,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 +1472,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,13 +1487,12 @@ "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", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", - "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "version": "1.17.15", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", "dependencies": { "@types/node": "*" } @@ -1662,19 +1507,25 @@ "http-proxy-middleware": "*" } }, + "node_modules/@types/http-proxy/node_modules/@types/node": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.1.0.tgz", + "integrity": "sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==", + "dependencies": { + "undici-types": "~6.13.0" + } + }, "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" + "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 +1535,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 +1555,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.7", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz", + "integrity": "sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==", + "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,17 +1585,22 @@ "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", + "dev": true, "dependencies": { "undici-types": "~5.26.4" } }, + "node_modules/@types/node/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 + }, "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": "*", @@ -1750,25 +1608,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 +1634,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 +1644,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", @@ -1831,11 +1680,10 @@ } }, "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==", + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "dev": true, - "license": "MIT", "dependencies": { "@types/yargs-parser": "*" } @@ -1844,14 +1692,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 +1706,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" @@ -1891,11 +1736,25 @@ } }, "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==", + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", "dev": true, - "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk/node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, "engines": { "node": ">=0.4.0" } @@ -1904,7 +1763,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 +1771,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 +1779,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.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dependencies": { "ms": "2.1.2" }, @@ -1941,14 +1797,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" @@ -1958,14 +1812,14 @@ } }, "node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -1993,7 +1847,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 +1856,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 +1871,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 +1879,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 +1903,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 +1915,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,113 +1954,95 @@ "node": ">= 6" } }, - "node_modules/archiver/node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" - }, - "node_modules/archiver/node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/archiver/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==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/archiver/node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "node_modules/archiver-utils/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==", "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" + "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/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", + "deprecated": "This package is no longer supported.", "optional": true, "dependencies": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" } }, + "node_modules/are-we-there-yet/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==", + "optional": true, + "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/arg": { "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" } }, "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" - } + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" }, "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 +2054,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 +2075,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 +2091,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 +2107,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 +2116,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 +2131,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 +2154,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 +2168,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 +2193,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 +2212,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 +2225,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 +2236,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" @@ -2430,13 +2248,13 @@ "dev": true }, "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", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dependencies": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" } }, "node_modules/bluebird": { @@ -2471,28 +2289,26 @@ "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==", - "license": "MIT", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.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==", + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", "dev": true, "funding": [ { @@ -2508,12 +2324,11 @@ "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" + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" @@ -2527,7 +2342,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 +2373,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 +2383,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 +2397,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,11 +2417,18 @@ "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/buffermaker/node_modules/long": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/long/-/long-1.1.2.tgz", + "integrity": "sha512-pjR3OP1X2VVQhCQlrq3s8UxugQsuoucwMOn9Yj/kN/61HMc+lDFJS5bvpNEHneZ9NVaSm8gNWxZvtGS7lqHb3Q==", + "engines": { + "node": ">=0.6" + } + }, "node_modules/buffers": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", @@ -2639,16 +2455,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.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", + "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", @@ -2671,47 +2485,33 @@ "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", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "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", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, "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", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -2726,7 +2526,6 @@ "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 +2545,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 +2554,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.30001651", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", + "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", "dev": true, "funding": [ { @@ -2779,14 +2576,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,17 +2594,18 @@ "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": { "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" @@ -2821,12 +2617,26 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "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 +2646,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 +2666,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 +2682,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 +2705,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 +2714,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 +2758,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 +2767,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 +2826,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 +2835,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 +2843,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 +2858,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 +2868,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 +2883,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 +2890,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 +2905,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" }, @@ -3072,24 +2926,10 @@ "node": ">= 10" } }, - "node_modules/compress-commons/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==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "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" }, @@ -3101,7 +2941,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 +2958,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 +2965,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 +3001,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 +3015,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 +3028,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" }, @@ -3229,25 +3058,11 @@ "node": ">= 10" } }, - "node_modules/crc32-stream/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==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "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", @@ -3268,14 +3083,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,16 +3098,29 @@ "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", - "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==" + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" }, "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" } @@ -3303,7 +3129,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 +3138,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 +3155,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 +3163,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 +3178,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 +3194,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 +3202,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", + "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" } @@ -3399,7 +3216,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 +3224,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 +3233,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 +3246,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 +3255,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 +3264,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 +3273,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" }, @@ -3478,12 +3288,25 @@ "readable-stream": "^2.0.2" } }, + "node_modules/duplexer2/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==", + "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/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" } @@ -3491,26 +3314,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.5.5", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz", + "integrity": "sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==", + "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 +3340,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 +3361,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 +3370,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 +3382,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 +3391,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 +3399,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 +3431,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 +3447,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 +3472,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 +3481,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 +3488,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 +3520,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" + "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_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": ">=4" } }, "node_modules/eslint": { @@ -3787,7 +3591,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 +3604,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 +3619,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 +3628,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 +3648,20 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "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.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -3872,12 +3680,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.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "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, + "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, - "license": "MIT" + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } }, "node_modules/espree": { "version": "7.3.1", @@ -3903,24 +3797,22 @@ } }, "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": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -3933,7 +3825,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 +3834,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 +3846,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 +3854,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 +3862,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 +3870,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" } @@ -4012,19 +3898,6 @@ "node": ">=8.3.0" } }, - "node_modules/exceljs/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==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/exceljs/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -4038,7 +3911,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 +3942,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 +3952,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 +3966,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 +4026,7 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/fast-csv": { "version": "4.3.6", @@ -4175,28 +4043,29 @@ "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/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" }, "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 +4073,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 +4091,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", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4243,7 +4108,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 +4126,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 +4139,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", @@ -4286,18 +4148,32 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/flat-cache/node_modules/rimraf": { + "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, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "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" + "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 +4185,6 @@ "url": "https://github.com/sponsors/RubenVerborgh" } ], - "license": "MIT", "engines": { "node": ">=4.0" }, @@ -4320,10 +4195,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.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -4339,7 +4213,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 +4224,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 +4237,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 +4245,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 +4253,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 +4260,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 +4276,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,23 +4307,10 @@ "node": ">=0.6" } }, - "node_modules/fstream/node_modules/rimraf": { - "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", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "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" } @@ -4452,14 +4319,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 +4338,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 +4352,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 +4360,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 +4379,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 +4388,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,14 +4399,13 @@ "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", + "deprecated": "Glob versions prior to v9 are no longer supported", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -4589,7 +4426,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" }, @@ -4612,11 +4448,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 +4471,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 +4486,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 +4497,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 +4508,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 +4519,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 +4541,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 +4566,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 +4605,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 +4614,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.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dependencies": { "ms": "2.1.2" }, @@ -4802,8 +4632,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", @@ -4822,9 +4651,9 @@ } }, "node_modules/http-proxy-middleware/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dependencies": { "ms": "2.1.2" }, @@ -4843,10 +4672,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "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", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -4856,10 +4684,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.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dependencies": { "ms": "2.1.2" }, @@ -4875,15 +4702,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 +4717,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 +4755,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", @@ -4951,11 +4774,10 @@ } }, "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, - "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -4974,7 +4796,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 +4804,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 +4812,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,21 +4821,62 @@ "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/ioredis": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.4.1.tgz", + "integrity": "sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==", + "dependencies": { + "@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.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, + "node_modules/ioredis/node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "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==", - "license": "MIT", "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" @@ -5024,34 +4885,24 @@ "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" + "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" }, @@ -5060,13 +4911,15 @@ } }, "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==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", "dev": true, - "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5076,7 +4929,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 +4937,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 +4950,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 +4958,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 +4968,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 +4993,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,31 +5003,27 @@ "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" } }, "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==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", @@ -5193,12 +5035,23 @@ "node": ">=10" } }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "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 +5066,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", @@ -5224,11 +5076,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==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -5245,15 +5096,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,16 +5112,12 @@ } }, "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.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dependencies": { "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": ">=14" - }, "funding": { "url": "https://github.com/sponsors/isaacs" }, @@ -5308,7 +5153,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 +5179,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 +5188,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 +5234,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 +5254,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 +5294,23 @@ } } }, + "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 +5326,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 +5338,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 +5354,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 +5371,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 +5380,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 +5405,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 +5418,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 +5433,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 +5448,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 +5467,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 +5484,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 +5493,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 +5513,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 +5526,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 +5553,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", @@ -5772,7 +5606,6 @@ "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 +5632,23 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "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 +5666,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 +5683,6 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -5853,7 +5695,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 +5714,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 +5729,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 +5739,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 +5791,29 @@ "js-yaml": "bin/js-yaml.js" } }, + "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 +5825,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 +5842,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 +5860,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", @@ -6014,11 +5877,24 @@ "setimmediate": "^1.0.5" } }, - "node_modules/kafka-node": { - "version": "5.0.0", + "node_modules/jszip/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==", + "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/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", @@ -6041,11 +5917,50 @@ "snappy": "^6.0.1" } }, + "node_modules/kafka-node/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/kafka-node/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==", + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/kafka-node/node_modules/denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/kafka-node/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==", + "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/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", + "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 +5970,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 +5979,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 +5986,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", @@ -6087,25 +5999,36 @@ "node": ">= 0.6.3" } }, + "node_modules/lazystream/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==", + "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/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", + "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 +6038,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 +6046,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 +6058,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 +6068,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 +6095,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 +6134,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", @@ -6224,10 +6147,9 @@ "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" }, "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", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.1.tgz", + "integrity": "sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA==", "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", @@ -6243,34 +6165,26 @@ "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", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/long/-/long-2.4.0.tgz", + "integrity": "sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ==", "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.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" }, "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" }, @@ -6281,18 +6195,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "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 +6227,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 +6235,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 +6256,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,32 +6263,28 @@ "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" } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "license": "MIT", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -6368,7 +6295,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 +6306,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 +6314,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 +6326,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 +6334,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 +6343,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 +6354,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 +6370,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 +6378,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 +6397,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 +6408,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 +6415,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 +6430,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 +6437,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 +6452,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 +6459,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 +6475,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 +6482,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 +6497,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 +6512,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 +6522,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", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", + "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", "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 +6553,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" }, @@ -6738,47 +6602,33 @@ "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", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "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", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, "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", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -6789,46 +6639,38 @@ "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.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "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" + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "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 +6685,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 +6694,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 +6705,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 +6718,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,17 +6727,18 @@ "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", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6907,14 +6747,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 +6764,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 +6772,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 +6780,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 +6789,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 +6810,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 +6832,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 +6857,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 +6864,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,16 +6883,19 @@ "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/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" + }, "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 +6914,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 +6931,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 +6940,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 +6948,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 +6956,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 +6964,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 +7018,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 +7040,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 +7049,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 +7057,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 +7082,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 +7098,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 +7107,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 +7116,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 +7125,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 +7137,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 +7163,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 +7172,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 +7184,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 +7193,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 +7205,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 +7214,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 +7222,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 +7255,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 +7267,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 +7281,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 +7292,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 +7307,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 +7334,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 +7346,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 +7355,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 +7366,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 +7383,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 +7399,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "license": "MIT", + "dev": true, "engines": { "node": ">=6" } @@ -7658,14 +7418,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 +7438,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 +7446,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 +7460,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,36 +7471,23 @@ "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", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "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" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/readdir-glob": { @@ -7780,7 +7522,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 +7529,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 +7565,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 +7573,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 +7587,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 +7604,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 +7616,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 +7634,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,38 +7642,31 @@ "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", + "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", "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" + "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 +7674,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" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" }, "node_modules/saxes": { "version": "5.0.1", @@ -7949,43 +7693,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 +7727,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 +7747,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 +7768,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 +7790,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 +7798,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 +7815,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 +7835,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 +7852,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 +7876,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 +7888,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 +7916,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 +7926,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 +7934,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" @@ -8239,24 +7947,22 @@ } }, "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", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", "dependencies": { "agent-base": "^7.1.1", "debug": "^4.3.4", - "socks": "^2.7.1" + "socks": "^2.8.3" }, "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", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dependencies": { "ms": "2.1.2" }, @@ -8272,15 +7978,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 +7994,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 +8004,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 +8025,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 +8039,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 +8048,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 +8060,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 +8081,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 +8089,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 +8098,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 +8106,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 +8136,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 +8151,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 +8201,19 @@ "node": ">=0.10.0" } }, - "node_modules/strip-ansi": { + "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-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 +8223,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 +8232,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", + "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": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, "node_modules/supports-color": { @@ -8540,7 +8250,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 +8262,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 +8274,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 +8285,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 +8314,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 +8323,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 +8355,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,29 +8363,45 @@ "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/bl": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", + "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", + "optional": true, + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } }, "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": { + "node_modules/tar-fs/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==", + "optional": true, + "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/tar-fs/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", @@ -8670,22 +8416,33 @@ "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, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dependencies": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "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 +8454,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 +8465,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 +8473,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 +8480,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 +8494,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", @@ -8759,15 +8506,13 @@ "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", @@ -8785,19 +8530,10 @@ "node": ">= 0.10.x" } }, - "node_modules/thriftrw/node_modules/long": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/long/-/long-2.4.0.tgz", - "integrity": "sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ==", - "engines": { - "node": ">=0.6" - } - }, "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 +8547,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 +8560,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 +8568,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 +8579,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 +8586,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 +8609,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 +8618,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 +8661,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", @@ -8967,7 +8695,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, - "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -8975,25 +8702,11 @@ "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==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, - "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -9006,7 +8719,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 +8731,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 +8748,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 +8763,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 +8795,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 +8806,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" + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", + "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==" }, "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 +8828,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 +8839,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" } @@ -9168,10 +8860,24 @@ "setimmediate": "~1.0.4" } }, + "node_modules/unzipper/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==", + "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/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.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", "dev": true, "funding": [ { @@ -9187,10 +8893,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 +8908,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "license": "BSD-2-Clause", + "dev": true, "dependencies": { "punycode": "^2.1.0" } @@ -9211,14 +8916,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 +8934,6 @@ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], - "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -9240,22 +8942,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==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, - "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", @@ -9269,7 +8968,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 +8977,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 +9025,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", @@ -9342,58 +9043,22 @@ } }, "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", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.1.tgz", + "integrity": "sha512-wQCXXVgfv/wUPOfb2x0ruxzwkcZfxcktz6JIMUaPLmcNhO4bZTwA/WtDWK74xV3F2dKu8YadrFv0qhwYjVEwhA==", "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", + "logform": "^2.6.1", + "readable-stream": "^3.6.2", "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" } @@ -9402,7 +9067,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 +9075,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 +9100,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 +9145,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 +9154,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 +9248,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 +9269,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 +9278,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 +9310,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 +9343,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 +9352,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 +9378,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 +9389,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 +9396,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", @@ -9721,19 +9428,6 @@ "engines": { "node": ">= 10" } - }, - "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", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } } } } diff --git a/health-services/project-factory/package.json b/health-services/project-factory/package.json index a91771378fa..5a80dcc7147 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.3.0", "main": "src/server/index.ts", "author": "Jagankumar ", "description": "Backend For Frontend service", @@ -10,11 +10,11 @@ "build": "yarn run build-ts", "build-ts": "tsc", "clean": "rm -rf ./dist", - "serve": "node dist/index.js", + "serve": "if [ \"$DEBUG\" = \"true\" ]; then node --inspect=0.0.0.0:9229 dist/index.js; else node dist/index.js; fi", "start": "yarn run dev", "test": "jest", "dev": "ts-node-dev --respawn src/server/index.ts", - "prod": "yarn build && yarn serve", + "prod": "if [ \"$DEBUG\" = \"true\" ]; then cp tsconfig.debug.json tsconfig.json; fi && yarn build && yarn serve", "watch-ts": "tsc --watch" }, "repository": { @@ -26,7 +26,7 @@ "axios": "1.6.8", "body-parser": "^1.20.2", "compression": "1.7.4", - "exceljs": "4.4.0", + "exceljs": "^4.4.0", "express": "^4.19.2", "hash-sum": "2.0.0", "helmet": "7.1.0", @@ -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..4f29fd481a8 100644 --- a/health-services/project-factory/src/server/api/campaignApis.ts +++ b/health-services/project-factory/src/server/api/campaignApis.ts @@ -1,19 +1,58 @@ import config from "../config"; -import { v4 as uuidv4 } from 'uuid'; +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 { immediateValidationForTargetSheet, validateSheetData, validateTargetSheetData } from '../validators/campaignValidators'; +import createAndSearch from "../config/createAndSearch"; +import { + getDataFromSheet, + generateActivityMessage, + throwError, + translateSchema, + replicateRequest, + appendProjectTypeToCapacity, + getLocalizedMessagesHandler, +} from "../utils/genericUtils"; +import { + immediateValidationForTargetSheet, + validateEmptyActive, + validateSheetData, + validateTargetSheetData, + validateViaSchemaSheetWise, +} from "../validators/campaignValidators"; import { callMdmsTypeSchema, getCampaignNumber } from "./genericApis"; -import { boundaryBulkUpload, convertToTypeData, generateHierarchy, generateProcessedFileAndPersist, getLocalizedName, reorderBoundariesOfDataAndValidate } from "../utils/campaignUtils"; -const _ = require('lodash'); -import { produceModifiedMessages } from "../kafka/Listener"; +import { + boundaryBulkUpload, + convertToTypeData, + generateHierarchy, + generateProcessedFileAndPersist, + getBoundaryOnWhichWeSplit, + getLocalizedName, + reorderBoundariesOfDataAndValidate, + checkIfSourceIsMicroplan, + createIdRequests, + createUniqueUserNameViaIdGen, + boundaryGeometryManagement, +} from "../utils/campaignUtils"; +const _ = require("lodash"); +import { produceModifiedMessages } from "../kafka/Producer"; import { createDataService } from "../service/dataManageService"; import { searchProjectTypeCampaignService } from "../service/campaignManageService"; import { getExcelWorkbookFromFileURL } from "../utils/excelUtils"; - - +import { + processTrackStatuses, + processTrackTypes, + resourceDataStatuses, +} from "../config/constants"; +import { persistTrack } from "../utils/processTrackUtils"; +import { checkAndGiveIfParentCampaignAvailable } from "../utils/onGoingCampaignUpdateUtils"; +import { validateMicroplanFacility } from "../validators/microplanValidators"; +import { + createPlanFacilityForMicroplan, + updateFacilityDetailsForMicroplan, +} from "../utils/microplanUtils"; +import { getTransformedLocale } from "../utils/localisationUtils"; +import { BoundaryModels } from "../models"; +import { searchBoundaryRelationshipDefinition } from "./coreApis"; /** * Enriches the campaign data with unique IDs and generates campaign numbers. @@ -23,15 +62,30 @@ 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); + logger.info(`ENRICHMENT:: generated id for the campaign ${requestBody.Campaign.id}`); + requestBody.Campaign.campaignNo = await getCampaignNumber( + requestBody, + config.values.idgen.format, + config.values.idgen.idName, + requestBody?.Campaign?.tenantId + ); + logger.info(`ENRICHMENT:: generated sequence no for the campaign ${requestBody.Campaign.campaignNo}`); for (const campaignDetails of requestBody?.Campaign?.CampaignDetails) { campaignDetails.id = uuidv4(); } } } -async function getAllFacilitiesInLoop(searchedFacilities: any[], facilitySearchParams: any, facilitySearchBody: any) { - const response = await httpRequest(config.host.facilityHost + config.paths.facilitySearch, facilitySearchBody, facilitySearchParams); +async function getAllFacilitiesInLoop( + searchedFacilities: any[], + facilitySearchParams: any, + facilitySearchBody: any +) { + const response = await httpRequest( + config.host.facilityHost + config.paths.facilitySearch, + facilitySearchBody, + facilitySearchParams + ); if (Array.isArray(response?.Facilities)) { searchedFacilities.push(...response?.Facilities); @@ -52,20 +106,24 @@ async function getAllFacilities(tenantId: string, requestBody: any) { // Retrieve all facilities for the given tenant ID const facilitySearchBody = { RequestInfo: requestBody?.RequestInfo, - Facility: { isPermanent: true } + Facility: { isPermanent: true }, }; const facilitySearchParams = { limit: 50, offset: 0, - tenantId: tenantId?.split('.')?.[0] + tenantId: tenantId?.split(".")?.[0], }; const searchedFacilities: any[] = []; let searchAgain = true; while (searchAgain) { - searchAgain = await getAllFacilitiesInLoop(searchedFacilities, facilitySearchParams, facilitySearchBody); + searchAgain = await getAllFacilitiesInLoop( + searchedFacilities, + facilitySearchParams, + facilitySearchBody + ); facilitySearchParams.offset += 50; } @@ -79,17 +137,21 @@ async function getAllFacilities(tenantId: string, requestBody: any) { * @param requestBody The request body containing additional parameters. * @returns An array of facilities. */ -async function getFacilitiesViaIds(tenantId: string, ids: any[], requestBody: any) { +async function getFacilitiesViaIds( + tenantId: string, + ids: any[], + requestBody: any +) { // Retrieve facilities by their IDs const facilitySearchBody: any = { RequestInfo: requestBody?.RequestInfo, - Facility: {} + Facility: {}, }; const facilitySearchParams = { limit: 50, offset: 0, - tenantId: tenantId?.split('.')?.[0] + tenantId: tenantId?.split(".")?.[0], }; const searchedFacilities: any[] = []; @@ -98,7 +160,11 @@ async function getFacilitiesViaIds(tenantId: string, ids: any[], requestBody: an for (let i = 0; i < ids.length; i += 50) { const chunkIds = ids.slice(i, i + 50); facilitySearchBody.Facility.id = chunkIds; - await getAllFacilitiesInLoop(searchedFacilities, facilitySearchParams, facilitySearchBody); + await getAllFacilitiesInLoop( + searchedFacilities, + facilitySearchParams, + facilitySearchBody + ); } return searchedFacilities; @@ -120,13 +186,16 @@ function getParamsViaElements(elements: any, request: any) { 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)) + } else if (element?.getValueViaPath) { + _.set( + params, + element?.keyPath, + _.get(request.body, element?.getValueViaPath) + ); } } } - return params + return params; } /** @@ -143,12 +212,14 @@ function changeBodyViaElements(elements: any, requestBody: any) { 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, {}) + } else if (element?.getValueViaPath) { + _.set( + requestBody, + element?.keyPath, + _.get(requestBody, element?.getValueViaPath) + ); + } else { + _.set(requestBody, element?.keyPath, {}); } } } @@ -169,122 +240,255 @@ function changeBodyViaElements(elements: any, requestBody: any) { // } // } -function updateErrorsForUser(newCreatedData: any[], newSearchedData: any[], errors: any[], createAndSearchConfig: any, userNameAndPassword: any[]) { +function updateErrorsForUser( + request: any, + newCreatedData: any[], + newSearchedData: any[], + errors: any[], + createAndSearchConfig: any, + userNameAndPassword: any[] +) { + const isSourceMicroplan = + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan"; 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: "" }) + errors.push({ + status: "CREATED", + rowNumber: createdElement["!row#number!"], + isUniqueIdentifier: isSourceMicroplan ? false : true, + uniqueIdentifier: _.get( + searchedElement, + createAndSearchConfig.uniqueIdentifier, + "" + ), + errorDetails: "", + }); userNameAndPassword.push({ userName: searchedElement?.user?.userName, password: createdElement?.user?.password, - rowNumber: createdElement["!row#number!"] - }) + 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!"]); + 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) { +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) { - if (createdElement[key] !== searchedElement[key] && key != '!row#number!') { + if ( + createdElement[key] !== searchedElement[key] && + key != "!row#number!" + ) { match = false; break; } } if (match) { foundMatch = true; + createdElement.id = searchedElement.id; newSearchedData.splice(newSearchedData.indexOf(searchedElement), 1); - errors.push({ status: "CREATED", rowNumber: createdElement["!row#number!"], isUniqueIdentifier: true, uniqueIdentifier: _.get(searchedElement, createAndSearchConfig.uniqueIdentifier, ""), errorDetails: "" }) + 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!"]); + 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) { +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[] = [] + }); + var errors: any[] = []; if (request?.body?.ResourceDetails?.type != "user") { if (request?.body?.ResourceDetails?.type == "facility") { newCreatedData?.forEach((element: any) => { - delete element.address - }) + delete element.address; + }); } - updateErrors(newCreatedData, newSearchedData, errors, createAndSearchConfig); - } - else { - var userNameAndPassword: any = [] - updateErrorsForUser(newCreatedData, newSearchedData, errors, createAndSearchConfig, userNameAndPassword); - request.body.userNameAndPassword = userNameAndPassword + updateErrors( + newCreatedData, + newSearchedData, + errors, + createAndSearchConfig + ); + updateFacilityDetailsForMicroplan(request, newCreatedData); + } else { + var userNameAndPassword: any = []; + updateErrorsForUser( + request, + newCreatedData, + newSearchedData, + errors, + createAndSearchConfig, + userNameAndPassword + ); + request.body.userNameAndPassword = userNameAndPassword; } - request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; - request.body.Activities = activities + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails + ? [...request?.body?.sheetErrorDetails, ...errors] + : errors; + request.body.Activities = activities; } -async function getUuidsError(request: any, response: any, mobileNumberRowNumberMapping: any) { - var errors: any[] = [] +async function getUuidsError( + request: any, + response: any, + mobileNumberRowNumberMapping: any +) { + var errors: any[] = []; var count = 0; - request.body.mobileNumberUuidsMapping = request.body.mobileNumberUuidsMapping ? request.body.mobileNumberUuidsMapping : {}; + request.body.mobileNumberUuidsMapping = request.body.mobileNumberUuidsMapping + ? request.body.mobileNumberUuidsMapping + : {}; for (const user of response.Individual) { if (!user?.userUuid) { - logger.info(`User with mobileNumber ${user?.mobileNumber} doesn't have userUuid`) - errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have userUuid` }) + logger.info( + `User with mobileNumber ${user?.mobileNumber} doesn't have userUuid` + ); + errors.push({ + status: "INVALID", + rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], + errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have userUuid`, + }); count++; - } - else if (!user?.userDetails?.username) { - logger.info(`User with mobileNumber ${user?.mobileNumber} doesn't have username`) - errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have username` }) + } else if (!user?.userDetails?.username) { + logger.info( + `User with mobileNumber ${user?.mobileNumber} doesn't have username` + ); + errors.push({ + status: "INVALID", + rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], + errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have username`, + }); count++; - } - else { - request.body.mobileNumberUuidsMapping[user?.mobileNumber] = { userUuid: user?.id, code: user?.userDetails?.username, rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber] } + } 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], + password: user?.userDetails?.password, + userServiceUuid: user?.userUuid, + }; } } if (count > 0) { - request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails + ? [...request?.body?.sheetErrorDetails, ...errors] + : errors; } } -const createBatchRequest = async (request: any, batch: any[], mobileNumberRowNumberMapping: any) => { +const createBatchRequest = async ( + request: any, + batch: any[], + mobileNumberRowNumberMapping: any +) => { const searchBody = { RequestInfo: request?.body?.RequestInfo, Individual: { - mobileNumber: batch - } + mobileNumber: batch, + }, }; const params = { limit: 55, offset: 0, tenantId: request?.body?.ResourceDetails?.tenantId, - includeDeleted: true + includeDeleted: true, }; logger.info("Individual search to validate the mobile no initiated"); - const response = await httpRequest(config.host.healthIndividualHost + config.paths.healthIndividualSearch, searchBody, params, undefined, undefined, undefined, undefined, true); + const response = await httpRequest( + config.host.healthIndividualHost + config.paths.healthIndividualSearch, + searchBody, + params, + undefined, + undefined, + undefined, + undefined, + true + ); if (!response) { - throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "Error occurred during user search while validating mobile number."); + throwError( + "COMMON", + 400, + "INTERNAL_SERVER_ERROR", + "Error occurred during user search while validating mobile number." + ); } if (config.values.notCreateUserIfAlreadyThere) { await getUuidsError(request, response, mobileNumberRowNumberMapping); @@ -296,8 +500,14 @@ const createBatchRequest = async (request: any, batch: any[], mobileNumberRowNum return []; }; -async function getUserWithMobileNumbers(request: any, mobileNumbers: any[], mobileNumberRowNumberMapping: any) { - logger.info("mobileNumbers to search: " + JSON.stringify(mobileNumbers)); +async function getUserWithMobileNumbers( + request: any, + mobileNumbers: any[], + mobileNumberRowNumberMapping: any +) { + logger.debug( + "mobileNumbers to search: " + getFormattedStringForDebug(mobileNumbers) + ); const BATCH_SIZE = 50; let allResults: any[] = []; @@ -305,7 +515,9 @@ async function getUserWithMobileNumbers(request: any, mobileNumbers: any[], mobi const batchPromises = []; for (let i = 0; i < mobileNumbers.length; i += BATCH_SIZE) { const batch = mobileNumbers.slice(i, i + BATCH_SIZE); - batchPromises.push(createBatchRequest(request, batch, mobileNumberRowNumberMapping)); + batchPromises.push( + createBatchRequest(request, batch, mobileNumberRowNumberMapping) + ); } // Wait for all batch requests to complete @@ -321,87 +533,179 @@ async function getUserWithMobileNumbers(request: any, mobileNumbers: any[], mobi return resultSet; } - async function matchUserValidation(createdData: any[], request: any) { var count = 0; - const errors = [] - const mobileNumbers = createdData.filter(item => item?.user?.mobileNumber).map(item => (item?.user?.mobileNumber)); + const errors = []; + const mobileNumbers = createdData + .filter((item) => item?.user?.mobileNumber) + .map((item) => item?.user?.mobileNumber); const mobileNumberRowNumberMapping = createdData.reduce((acc, curr) => { acc[curr.user.mobileNumber] = curr["!row#number!"]; return acc; }, {}); - logger.info("mobileNumberRowNumberMapping : " + JSON.stringify(mobileNumberRowNumberMapping)); - const mobileNumberResponse = await getUserWithMobileNumbers(request, mobileNumbers, mobileNumberRowNumberMapping); + logger.debug( + "mobileNumberRowNumberMapping : " + + getFormattedStringForDebug(mobileNumberRowNumberMapping) + ); + const mobileNumberResponse = await getUserWithMobileNumbers( + request, + mobileNumbers, + mobileNumberRowNumberMapping + ); for (const key in mobileNumberRowNumberMapping) { - if (mobileNumberResponse.has(key) && !config.values.notCreateUserIfAlreadyThere) { - errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[key], errorDetails: `User with mobileNumber ${key} already exists` }) + if ( + mobileNumberResponse.has(key) && + !config.values.notCreateUserIfAlreadyThere + ) { + if (Array.isArray(mobileNumberRowNumberMapping[key])) { + for (const row of mobileNumberRowNumberMapping[key]) { + errors.push({ + status: "INVALID", + rowNumber: row.row, + sheetName: row.sheetName, + errorDetails: `User with contact number ${key} already exists`, + }); + } + } else { + errors.push({ + status: "INVALID", + rowNumber: mobileNumberRowNumberMapping[key], + errorDetails: `User with contact number ${key} already exists`, + }); + } count++; } } if (count) { - request.body.ResourceDetails.status = "invalid" + request.body.ResourceDetails.status = "invalid"; } logger.info("Invalid resources count : " + count); - request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; + 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) { +function matchViaUserIdAndCreationTime( + createdData: any[], + searchedData: any[], + request: any, + creationTime: any, + createAndSearchConfig: any, + activities: any +) { var matchingSearchData = []; - const userUuid = request?.body?.RequestInfo?.userInfo?.uuid + 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) { + if ( + data?.auditDetails?.createdBy == userUuid && + data?.auditDetails?.createdTime >= creationTime + ) { matchingSearchData.push(data); count++; } } - } - else { + } else { count = searchedData.length; matchingSearchData = searchedData; } if (count < createdData.length) { - request.body.ResourceDetails.status = "PERSISTER_ERROR" + request.body.ResourceDetails.status = "PERSISTER_ERROR"; } - matchCreatedAndSearchedData(createdData, matchingSearchData, request, createAndSearchConfig, activities); + matchCreatedAndSearchedData( + createdData, + matchingSearchData, + request, + createAndSearchConfig, + activities + ); logger.info("New created resources count : " + count); } -async function processSearch(createAndSearchConfig: any, request: any, params: any) { +async function processSearch( + createAndSearchConfig: any, + request: any, + params: any +) { setSearchLimits(createAndSearchConfig, request, params); - const arraysToMatch = await performSearch(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 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) { +function setLimitOrOffset( + limitOrOffsetConfig: any, + params: any, + requestBody: any +) { if (limitOrOffsetConfig) { if (limitOrOffsetConfig?.isInParams) { - _.set(params, limitOrOffsetConfig?.keyPath, parseInt(limitOrOffsetConfig?.value)); + _.set( + params, + limitOrOffsetConfig?.keyPath, + parseInt(limitOrOffsetConfig?.value) + ); } if (limitOrOffsetConfig?.isInBody) { - _.set(requestBody, limitOrOffsetConfig?.keyPath, parseInt(limitOrOffsetConfig?.value)); + _.set( + requestBody, + limitOrOffsetConfig?.keyPath, + parseInt(limitOrOffsetConfig?.value) + ); } } } -async function performSearch(createAndSearchConfig: any, request: any, params: any) { +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); + 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)) { + if ( + resultArray.length < + parseInt(createAndSearchConfig?.searchDetails?.searchLimit?.value) + ) { searchAgain = false; } } else { @@ -412,21 +716,32 @@ async function performSearch(createAndSearchConfig: any, request: any, params: a return arraysToMatch; } -function updateOffset(createAndSearchConfig: any, params: any, requestBody: any) { - const offsetConfig = createAndSearchConfig?.searchDetails?.searchOffset - const limit = createAndSearchConfig?.searchDetails?.searchLimit?.value +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))); + _.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))); + _.set( + requestBody, + offsetConfig?.keyPath, + parseInt(_.get(requestBody, offsetConfig?.keyPath) + parseInt(limit)) + ); } } } - -async function processSearchAndValidation(request: any, createAndSearchConfig: any, dataFromSheet: any[]) { +async function processSearchAndValidation(request: any) { // if (request?.body?.dataToSearch?.length > 0) { // const params: any = getParamsViaElements(createAndSearchConfig?.searchDetails?.searchElements, request); // changeBodyViaElements(createAndSearchConfig?.searchDetails?.searchElements, request) @@ -435,36 +750,45 @@ async function processSearchAndValidation(request: any, createAndSearchConfig: a // matchData(request, request.body.dataToSearch, arraysToMatch, createAndSearchConfig) // } if (request?.body?.ResourceDetails?.type == "user") { - await enrichEmployees(request?.body?.dataToCreate, request) - await matchUserValidation(request.body.dataToCreate, request) + await enrichEmployees(request?.body?.dataToCreate, request); + await matchUserValidation(request.body.dataToCreate, request); } } async function getEmployeesBasedOnUuids(dataToCreate: any[], request: any) { const searchBody = { - RequestInfo: request?.body?.RequestInfo + RequestInfo: request?.body?.RequestInfo, }; const tenantId = request?.body?.ResourceDetails?.tenantId; const searchUrl = config.host.hrmsHost + config.paths.hrmsEmployeeSearch; logger.info(`Waiting for 10 seconds`); - await new Promise(resolve => setTimeout(resolve, 10000)); + await new Promise((resolve) => setTimeout(resolve, 10000)); const chunkSize = 50; let employeesSearched: any[] = []; for (let i = 0; i < dataToCreate.length; i += chunkSize) { const chunk = dataToCreate.slice(i, i + chunkSize); - const uuids = chunk.map((data: any) => data.uuid).join(','); + const uuids = chunk.map((data: any) => data.uuid).join(","); const params = { tenantId: tenantId, uuids: uuids, limit: 51, - offset: 0 + offset: 0, }; try { - const response = await httpRequest(searchUrl, searchBody, params, undefined, undefined, undefined, undefined, true); + const response = await httpRequest( + searchUrl, + searchBody, + params, + undefined, + undefined, + undefined, + undefined, + true + ); if (response && response.Employees) { employeesSearched = employeesSearched.concat(response.Employees); } else { @@ -472,104 +796,311 @@ async function getEmployeesBasedOnUuids(dataToCreate: any[], request: any) { } } catch (error: any) { console.log(error); - throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", error.message || "Some internal error occurred while searching employees"); + throwError( + "COMMON", + 500, + "INTERNAL_SERVER_ERROR", + error.message || + "Some internal error occurred while searching employees" + ); } } return employeesSearched; } - - - - - // Confirms the creation of resources by matching created and searched data. -async function confirmCreation(createAndSearchConfig: any, request: any, dataToCreate: any[], creationTime: any, activities: any) { +async function confirmCreation( + createAndSearchConfig: any, + request: any, + dataToCreate: any[], + creationTime: any, + activities: any +) { // Confirm creation of resources by matching data // wait for 5 seconds if (request?.body?.ResourceDetails?.type != "user") { - const params: any = getParamsViaElements(createAndSearchConfig?.searchDetails?.searchElements, request); - const arraysToMatch = await processSearch(createAndSearchConfig, request, params) - matchViaUserIdAndCreationTime(dataToCreate, arraysToMatch, request, creationTime, createAndSearchConfig, activities) - } - else { - const arraysToMatch = await getEmployeesBasedOnUuids(dataToCreate, request) - matchViaUserIdAndCreationTime(dataToCreate, arraysToMatch, request, creationTime, createAndSearchConfig, activities) + const params: any = getParamsViaElements( + createAndSearchConfig?.searchDetails?.searchElements, + request + ); + const arraysToMatch = await processSearch( + createAndSearchConfig, + request, + params + ); + matchViaUserIdAndCreationTime( + dataToCreate, + arraysToMatch, + request, + creationTime, + createAndSearchConfig, + activities + ); + } else { + const arraysToMatch = await getEmployeesBasedOnUuids(dataToCreate, request); + matchViaUserIdAndCreationTime( + dataToCreate, + arraysToMatch, + request, + creationTime, + createAndSearchConfig, + activities + ); } } -async function processValidateAfterSchema(dataFromSheet: any, request: any, createAndSearchConfig: any, localizationMap?: { [key: string]: string }) { +async function processValidateAfterSchema( + dataFromSheet: any, + request: any, + createAndSearchConfig: any, + localizationMap?: { [key: string]: string } +) { try { - const typeData = await convertToTypeData(request, dataFromSheet, createAndSearchConfig, request.body, localizationMap) + validateEmptyActive(dataFromSheet, request?.body?.ResourceDetails?.type, localizationMap); + if ( + request?.body?.ResourceDetails?.additionalDetails?.source == + "microplan" && + request?.body?.ResourceDetails?.type == "facility" + ) { + validateMicroplanFacility(request, dataFromSheet, localizationMap); + } + 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 processSearchAndValidation(request); + await reorderBoundariesOfDataAndValidate(request, localizationMap); await generateProcessedFileAndPersist(request, localizationMap); } catch (error) { - console.log(error) + console.log(error); await handleResouceDetailsError(request, error); } } -async function processValidate(request: any, localizationMap?: { [key: string]: string }) { +export async function processValidateAfterSchemaSheetWise( + request: any, + createAndSearchConfig: any, + localizationMap?: { [key: string]: string } +) { + if ( + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" && + request.body.ResourceDetails.type == "user" + ) { + await generateProcessedFileAndPersist(request, localizationMap); + } +} + +async function processSheetWise( + forCreate: any, + dataFromSheet: any, + request: any, + createAndSearchConfig: any, + translatedSchema: any, + localizationMap?: { [key: string]: string } +) { + try { + const errorMap: any = await validateViaSchemaSheetWise( + dataFromSheet, + translatedSchema, + request, + localizationMap + ); + enrichErrorIfSheetInvalid(request, errorMap); + await processSearchAndValidation(request); + if (request?.body?.sheetErrorDetails?.length > 0) { + request.body.ResourceDetails.status = resourceDataStatuses.invalid; + await generateProcessedFileAndPersist(request, localizationMap); + } else { + if (forCreate) { + await processAfterValidation( + dataFromSheet, + createAndSearchConfig, + request, + localizationMap + ); + } else { + await processValidateAfterSchemaSheetWise( + request, + createAndSearchConfig, + localizationMap + ); + } + } + } catch (error) { + console.log(error); + await handleResouceDetailsError(request, error); + } +} + +function enrichErrorIfSheetInvalid(request: any, errorMap: any) { + if (Object.keys(errorMap).length > 0) { + var sheetErrorDetails = []; + for (const sheetName of Object.keys(errorMap)) { + const errorData = errorMap[sheetName]; + for (const row of Object.keys(errorData)) { + if (errorData[row].length > 0) { + const errorDetails = errorData[row].join(", "); + sheetErrorDetails.push({ + status: "INVALID", + sheetName: sheetName, + rowNumber: row, + errorDetails: errorDetails, + }); + } + } + } + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails + ? [...request?.body?.sheetErrorDetails, ...sheetErrorDetails] + : sheetErrorDetails; + } +} + +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') { + const createAndSearchConfig = createAndSearch[type]; + const dataFromSheet: any = await getDataFromSheet( + request, + request?.body?.ResourceDetails?.fileStoreId, + request?.body?.ResourceDetails?.tenantId, + createAndSearchConfig, + null, + localizationMap + ); + if (type == "boundaryWithTarget") { + const hierarchyType = request?.body?.ResourceDetails?.hierarchyType; + const hierarchyModule = `${config.localisation.boundaryPrefix + }-${getTransformedLocale(hierarchyType)}`?.toLowerCase(); + const localizationMapForHierarchy = await getLocalizedMessagesHandler( + request, + request?.body?.ResourceDetails?.tenantId, + hierarchyModule + ); + localizationMap = { + ...localizationMap, + ...localizationMapForHierarchy, + }; + let differentTabsBasedOnLevel = await getBoundaryOnWhichWeSplit(request, request?.body?.ResourceDetails?.tenantId); + 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); - logger.info("target sheet format validation completed and starts with data validation"); - validateTargetSheetData(dataFromSheet, request, createAndSearchConfig?.boundaryValidation, localizationMap); - } - - else { + await immediateValidationForTargetSheet( + request, + dataFromSheet, + differentTabsBasedOnLevel, + localizationMap + ); + logger.info( + "target sheet format validation completed and starts with data validation" + ); + validateTargetSheetData( + dataFromSheet, + request, + createAndSearchConfig?.boundaryValidation, + differentTabsBasedOnLevel, + localizationMap + ); + } else { let schema: any; if (type == "facility" || type == "user") { - const mdmsResponse = await callMdmsTypeSchema(request, tenantId, type); - schema = mdmsResponse + const isUpdate = request?.body?.parentCampaignObject ? true : false; + if ( + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" + ) { + schema = await callMdmsTypeSchema( + request, + tenantId, + isUpdate, + type, + "microplan" + ); + } else { + schema = await callMdmsTypeSchema(request, tenantId, isUpdate, type); + } } const translatedSchema = await translateSchema(schema, localizationMap); - await validateSheetData(dataFromSheet, request, translatedSchema, createAndSearchConfig?.boundaryValidation, localizationMap) - processValidateAfterSchema(dataFromSheet, request, createAndSearchConfig, localizationMap) + if (Array.isArray(dataFromSheet)) { + if ( + request?.body?.ResourceDetails?.additionalDetails?.source != "microplan" + ) { + await validateSheetData( + dataFromSheet, + request, + translatedSchema, + createAndSearchConfig?.boundaryValidation, + localizationMap + ); + } + processValidateAfterSchema( + dataFromSheet, + request, + createAndSearchConfig, + localizationMap + ); + } else { + if (dataFromSheet && Object.keys(dataFromSheet).length > 0) { + processSheetWise( + false, + dataFromSheet, + request, + createAndSearchConfig, + translatedSchema, + localizationMap + ); + } else { + throwError( + "COMMON", + 400, + "VALIDATION_ERROR", + "No data filled in the sheet." + ); + } + } } } 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) { - const code = role.toUpperCase().split(' ').join('_') - newRoles.push({ name: role, code: code, tenantId: request?.body?.ResourceDetails?.tenantId }) + var newRoles: any[] = []; + if (!Array.isArray(employee.user.roles)) { + const rolesArray = employee.user.roles + .split(",") + .map((role: any) => role.trim()); + for (const role of rolesArray) { + const code = role.toUpperCase().split(" ").join("_"); + newRoles.push({ + name: role, + code: code, + tenantId: request?.body?.ResourceDetails?.tenantId, + }); + } + employee.user.roles = newRoles; } - 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 generateUserPassword() { // Function to generate a random lowercase letter function getRandomLowercaseLetter() { - const letters = 'abcdefghijklmnopqrstuvwxyz'; + const letters = "abcdefghijklmnopqrstuvwxyz"; return letters.charAt(Math.floor(Math.random() * letters.length)); } // Function to generate a random uppercase letter function getRandomUppercaseLetter() { - const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; return letters.charAt(Math.floor(Math.random() * letters.length)); } @@ -594,20 +1125,6 @@ function generateUserPassword() { return `${firstSequence}@${randomNumber}`; } - -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}`; - const generatedPassword = config?.user?.userPasswordAutoGenerate == "true" ? generateUserPassword() : config?.user?.userDefaultPassword - user.userName = generatedCode; - user.password = generatedPassword; - employee.code = generatedCode - }); -} - async function enrichJurisdictions(employee: any, request: any) { employee.jurisdictions = [ { @@ -615,91 +1132,199 @@ async function enrichJurisdictions(employee: any, request: any) { boundaryType: config.values.userMainBoundaryType, boundary: config.values.userMainBoundary, hierarchy: request?.body?.ResourceDetails?.hierarchyType, - roles: employee?.user?.roles - } - ] + roles: employee?.user?.roles, + }, + ]; } async function enrichEmployees(employees: any[], request: any) { - convertUserRoles(employees, request) + convertUserRoles(employees, request); + const idRequests = createIdRequests(employees); + request.body.idRequests = idRequests; + let result = await createUniqueUserNameViaIdGen(request); + var i = 0; for (const employee of employees) { - enrichUserNameAndPassword(employees) - await enrichJurisdictions(employee, request) + const { user } = employee; + const generatedPassword = + config?.user?.userPasswordAutoGenerate == "true" + ? generateUserPassword() + : config?.user?.userDefaultPassword; + user.userName = result?.idResponses?.[i]?.id; + user.password = generatedPassword; + employee.code = result?.idResponses?.[i]?.id; + await enrichJurisdictions(employee, request); if (employee?.user) { - employee.user.tenantId = request?.body?.ResourceDetails?.tenantId - employee.user.dob = 0 + employee.user.tenantId = request?.body?.ResourceDetails?.tenantId; + employee.user.dob = 0; } + i++; } } -function enrichDataToCreateForUser(dataToCreate: any[], responsePayload: any, request: any) { +function enrichDataToCreateForUser( + dataToCreate: any[], + responsePayload: any, + request: any +) { const createdEmployees = responsePayload?.Employees; - // create an object which have keys as employee.code and values as employee.uuid + // create an object which have keys as employee.code and values as employee.uuid const employeeMap = createdEmployees.reduce((map: any, employee: any) => { - map[employee.code] = employee.uuid; + map[employee.code] = { + uuid: employee?.uuid, + userServiceUuid: employee?.user?.userServiceUuid, + }; return map; }, {}); for (const employee of dataToCreate) { - if (!employee?.uuid && employeeMap[employee?.code]) { - employee.uuid = employeeMap[employee?.code]; + const mappedEmployee = employeeMap[employee?.code]; + if (mappedEmployee) { + if (!employee?.userServiceUuid) { + employee.userServiceUuid = mappedEmployee.userServiceUuid; + } + if (!employee?.uuid) { + employee.uuid = mappedEmployee.uuid; + } } } } -async function handeFacilityProcess(request: any, createAndSearchConfig: any, params: any, activities: any[], newRequestBody: any) { +async function handeFacilityProcess( + request: any, + createAndSearchConfig: any, + params: any, + activities: any[], + newRequestBody: any +) { for (const facility of newRequestBody.Facilities) { - facility.address = {} + facility.address = {}; } - var responsePayload = await httpRequest(createAndSearchConfig?.createBulkDetails?.url, newRequestBody, params, "post", undefined, undefined, true); - var activity = await generateActivityMessage(request?.body?.ResourceDetails?.tenantId, request.body, newRequestBody, responsePayload, "facility", createAndSearchConfig?.createBulkDetails?.url, responsePayload?.statusCode) - logger.info(`Activity : ${createAndSearchConfig?.createBulkDetails?.url} status: ${responsePayload?.statusCode}`); + var responsePayload = await httpRequest( + createAndSearchConfig?.createBulkDetails?.url, + newRequestBody, + params, + "post", + undefined, + undefined, + true + ); + var activity = await generateActivityMessage( + request?.body?.ResourceDetails?.tenantId, + request.body, + newRequestBody, + responsePayload, + "facility", + createAndSearchConfig?.createBulkDetails?.url, + responsePayload?.statusCode + ); + logger.info( + `Activity : ${createAndSearchConfig?.createBulkDetails?.url} status: ${responsePayload?.statusCode}` + ); activities.push(activity); } - -async function handleUserProcess(request: any, createAndSearchConfig: any, params: any, dataToCreate: any[], activities: any[], newRequestBody: any) { +async function handleUserProcess( + request: any, + createAndSearchConfig: any, + params: any, + dataToCreate: any[], + activities: any[], + newRequestBody: any +) { if (config.values.notCreateUserIfAlreadyThere) { - var Employees: any[] = [] + var Employees: any[] = []; if (request.body?.mobileNumberUuidsMapping) { for (const employee of newRequestBody.Employees) { - if (request.body.mobileNumberUuidsMapping[employee?.user?.mobileNumber]) { - logger.info(`User with mobile number ${employee?.user?.mobileNumber} already exist`); - } - else { - Employees.push(employee) + if ( + request.body.mobileNumberUuidsMapping[employee?.user?.mobileNumber] + ) { + logger.info( + `User with mobile number ${employee?.user?.mobileNumber} already exist` + ); + } else { + Employees.push(employee); } } } - newRequestBody.Employees = Employees + newRequestBody.Employees = Employees; } if (newRequestBody.Employees.length > 0) { - var responsePayload = await httpRequest(createAndSearchConfig?.createBulkDetails?.url, newRequestBody, params, "post", undefined, undefined, true, true); + var responsePayload = await httpRequest( + createAndSearchConfig?.createBulkDetails?.url, + newRequestBody, + params, + "post", + undefined, + undefined, + true, + false + ); if (responsePayload?.Employees && responsePayload?.Employees?.length > 0) { enrichDataToCreateForUser(dataToCreate, responsePayload, request); + } else { + throwError( + "COMMON", + 500, + "INTERNAL_SERVER_ERROR", + "Some internal server error occured during user creation." + ); } - else { - throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Some internal server error occured during user creation."); - } - var activity = await generateActivityMessage(request?.body?.ResourceDetails?.tenantId, request.body, newRequestBody, responsePayload, "user", createAndSearchConfig?.createBulkDetails?.url, responsePayload?.statusCode) - logger.info(`Activity : ${createAndSearchConfig?.createBulkDetails?.url} status: ${responsePayload?.statusCode}`); + var activity = await generateActivityMessage( + request?.body?.ResourceDetails?.tenantId, + request.body, + newRequestBody, + responsePayload, + "user", + createAndSearchConfig?.createBulkDetails?.url, + responsePayload?.statusCode + ); + logger.info( + `Activity : ${createAndSearchConfig?.createBulkDetails?.url} status: ${responsePayload?.statusCode}` + ); activities.push(activity); } } async function enrichAlreadyExsistingUser(request: any) { - if (request.body.ResourceDetails.type == "user" && request?.body?.mobileNumberUuidsMapping) { + if ( + request.body.ResourceDetails.type == "user" && + request?.body?.mobileNumberUuidsMapping + ) { for (const employee of request.body.dataToCreate) { - if (request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber]) { - 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; + if ( + request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber] + ) { + 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 = + request?.body?.mobileNumberUuidsMapping[ + employee?.user?.mobileNumber + ].password; + employee.user.userServiceUuid = + request?.body?.mobileNumberUuidsMapping[ + employee?.user?.mobileNumber + ].userServiceUuid; } } } } -async function performAndSaveResourceActivity(request: any, createAndSearchConfig: any, params: any, type: any, localizationMap?: { [key: string]: string }) { +async function performAndSaveResourceActivity( + request: any, + createAndSearchConfig: any, + params: any, + type: any, + localizationMap?: { [key: string]: string } +) { logger.info(type + " create data "); if (createAndSearchConfig?.createBulkDetails?.limit) { const limit = createAndSearchConfig?.createBulkDetails?.limit; @@ -713,20 +1338,46 @@ async function performAndSaveResourceActivity(request: any, createAndSearchConfi const chunkData = dataToCreate.slice(start, end); // Get a chunk of data const newRequestBody: any = { RequestInfo: request?.body?.RequestInfo, - } - _.set(newRequestBody, createAndSearchConfig?.createBulkDetails?.createPath, chunkData); + }; + _.set( + newRequestBody, + createAndSearchConfig?.createBulkDetails?.createPath, + chunkData + ); creationTime = Date.now(); - if (type == "facility") { - await handeFacilityProcess(request, createAndSearchConfig, params, activities, newRequestBody); - } - else if (type == "user") { - await handleUserProcess(request, createAndSearchConfig, params, chunkData, activities, newRequestBody); + if (type == "facility" || type == "facilityMicroplan") { + await handeFacilityProcess( + request, + createAndSearchConfig, + params, + activities, + newRequestBody + ); + } else if (type == "user") { + await handleUserProcess( + request, + createAndSearchConfig, + params, + chunkData, + activities, + newRequestBody + ); } + // wait for 5 seconds after each chunk + logger.info(`Waiting for 5 seconds after each chunk`); + await new Promise((resolve) => setTimeout(resolve, 5000)); } await enrichAlreadyExsistingUser(request); - logger.info(`Waiting for 10 seconds`); - await new Promise(resolve => setTimeout(resolve, 10000)); - await confirmCreation(createAndSearchConfig, request, dataToCreate, creationTime, activities); + logger.info(`Final waiting for 10 seconds`); + await new Promise((resolve) => setTimeout(resolve, 10000)); + await confirmCreation( + createAndSearchConfig, + request, + dataToCreate, + creationTime, + activities + ); + await createPlanFacilityForMicroplan(request, localizationMap); } await generateProcessedFileAndPersist(request, localizationMap); } @@ -735,13 +1386,33 @@ async function performAndSaveResourceActivity(request: any, createAndSearchConfi * Processes generic requests such as create or validate. * @param request The HTTP request object. */ -async function processGenericRequest(request: any, localizationMap?: { [key: string]: string }) { +async function processGenericRequest( + request: any, + localizationMap?: { [key: string]: string } +) { // Process generic requests - if (request?.body?.ResourceDetails?.action == "create") { - await processCreate(request, localizationMap) + if ( + request?.body?.ResourceDetails?.type != "boundary" && + request?.body?.ResourceDetails?.type != "boundaryManagement" + ) { + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + if ( + campaignObject?.additionalDetails?.resourceDistributionStrategy == + "HOUSE_TO_HOUSE" + ) { + request.body.showFixedPost = false; + } else { + request.body.showFixedPost = true; + } + request.body.projectTypeCode = campaignObject?.projectType; + await checkAndGiveIfParentCampaignAvailable(request, campaignObject); } - else { - await processValidate(request, localizationMap) + + if (request?.body?.ResourceDetails?.action == "create") { + await processCreate(request, localizationMap); + } else { + await processValidate(request, localizationMap); } } @@ -749,60 +1420,139 @@ async function handleResouceDetailsError(request: any, error: any) { var stringifiedError: any; if (error?.description || error?.message) { stringifiedError = JSON.stringify({ - status: error.status || '', - code: error.code || '', - description: error.description || '', - message: error.message || '' + status: error.status || "", + code: error.code || "", + description: error.description || "", + message: error.message || "", }); - } - else { - if (typeof error == "object") - stringifiedError = JSON.stringify(error); + } else { + if (typeof error == "object") stringifiedError = JSON.stringify(error); else { - stringifiedError = error + stringifiedError = error; } } - logger.error("Error while processing after validation : " + error) + 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: stringifiedError + error: stringifiedError, + }; + const persistMessage: any = { + ResourceDetails: request.body.ResourceDetails, }; - const persistMessage: any = { ResourceDetails: request.body.ResourceDetails } if (request?.body?.ResourceDetails?.action == "create") { - persistMessage.ResourceDetails.additionalDetails = { error: stringifiedError } + 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); + await new Promise((resolve) => setTimeout(resolve, 2000)); + + const activities = request?.body?.Activities; + const chunkPromises = []; + for (let i = 0; i < activities.length; i += 10) { + const chunk = activities.slice(i, Math.min(i + 10, activities.length)); + const activityObject: any = { Activities: chunk }; + chunkPromises.push( + produceModifiedMessages( + activityObject, + config?.kafka?.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC + ) + ); + } + await Promise.all(chunkPromises); + } +} + +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 }) { +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; - 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") { + validateEmptyActive(dataFromSheet, request?.body?.ResourceDetails?.type, localizationMap); + if ( + request?.body?.ResourceDetails?.additionalDetails?.source == + "microplan" && + request.body.ResourceDetails.type == "user" + ) { + await processSearchAndValidation(request); + } else { + const typeData = await convertToTypeData( + request, + dataFromSheet, + createAndSearchConfig, + request.body, + localizationMap + ); + request.body.dataToCreate = typeData.createData; + request.body.dataToSearch = typeData.searchData; + await processSearchAndValidation(request); + 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) { - console.log(error) - await handleResouceDetailsError(request, error) + console.log(error); + await persistCreationProcess(request, processTrackStatuses.failed); + await handleResouceDetailsError(request, error); } + await persistCreationProcess(request, processTrackStatuses.completed); } /** @@ -813,28 +1563,151 @@ 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") { + if (type == "boundary" || type == "boundaryManagement") { boundaryBulkUpload(request, localizationMap); + } else if (type == "boundaryGeometryManagement") { + await boundaryGeometryManagement(request, localizationMap); + } else { + // 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 + ); + const schema = await getSchema(request, tenantId, type, campaignType); + await processAfterGettingSchema( + dataFromSheet, + schema, + request, + createAndSearchConfig, + 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") { - logger.info("Fetching schema to validate the created data for type: " + type); - const mdmsResponse = await callMdmsTypeSchema(request, tenantId, type); - schema = mdmsResponse +} + +async function getSchema( + request: any, + tenantId: string, + type: string, + campaignType: string +) { + let schema: any; + const isUpdate = request?.body?.parentCampaignObject ? true : false; + if (type == "facility") { + logger.info( + "Fetching schema to validate the created data for type: " + type + ); + const mdmsResponse = await callMdmsTypeSchema( + request, + tenantId, + isUpdate, + type + ); + schema = mdmsResponse; + } else if (type == "facilityMicroplan") { + const mdmsResponse = await callMdmsTypeSchema( + request, + tenantId, + isUpdate, + "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 + ); + if ( + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" + ) { + const mdmsResponse = await callMdmsTypeSchema( + request, + tenantId, + isUpdate, + type, + "microplan" + ); + schema = mdmsResponse; + } else { + const mdmsResponse = await callMdmsTypeSchema( + request, + tenantId, + isUpdate, + type + ); + schema = mdmsResponse; } - else if (type == "user") { - logger.info("Fetching schema to validate the created data for type: " + type); - const mdmsResponse = await callMdmsTypeSchema(request, tenantId, type); - schema = mdmsResponse + } + return schema; +} + +async function processAfterGettingSchema( + dataFromSheet: any, + schema: any, + request: any, + createAndSearchConfig: any, + localizationMap?: any +) { + logger.info("translating schema"); + const translatedSchema = await translateSchema(schema, localizationMap); + if (Array.isArray(dataFromSheet)) { + await validateSheetData( + dataFromSheet, + request, + translatedSchema, + createAndSearchConfig?.boundaryValidation, + localizationMap + ); + logger.info("validation done sucessfully"); + processAfterValidation( + dataFromSheet, + createAndSearchConfig, + request, + localizationMap + ); + } else { + if (dataFromSheet && Object.keys(dataFromSheet).length > 0) { + processSheetWise( + true, + dataFromSheet, + request, + createAndSearchConfig, + translatedSchema, + localizationMap + ); + } else { + throwError( + "COMMON", + 400, + "VALIDATION_ERROR", + "No data filled in the sheet." + ); } - logger.info("translating schema") - const translatedSchema = await translateSchema(schema, localizationMap); - await validateSheetData(dataFromSheet, request, translatedSchema, createAndSearchConfig?.boundaryValidation, localizationMap); - logger.info("validation done sucessfully") - processAfterValidation(dataFromSheet, createAndSearchConfig, request, localizationMap) } } @@ -843,33 +1716,65 @@ 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") { + 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) { + const action = + resource?.type === "boundaryWithTarget" ? "validate" : "create"; + // if (resource.type != "boundaryWithTarget") { const resourceDetails = { type: resource.type, fileStoreId: resource.filestoreId, tenantId: request?.body?.CampaignDetails?.tenantId, - action: "create", + action: action, hierarchyType: request?.body?.CampaignDetails?.hierarchyType, additionalDetails: {}, - campaignId: request?.body?.CampaignDetails?.id + campaignId: request?.body?.CampaignDetails?.id, }; - logger.info(`Creating the resources for type ${resource.type}`) - logger.debug("resourceDetails " + getFormattedStringForDebug(resourceDetails)) + 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) + ResourceDetails: resourceDetails, + }; + const req = replicateRequest(request, createRequestBody); + const res: any = await createDataService(req); if (res?.id) { - resource.createResourceId = 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) { @@ -878,46 +1783,121 @@ async function confirmProjectParentCreation(request: any, projectId: any) { Projects: [ { id: projectId, - tenantId: request.body.CampaignDetails.tenantId - } - ] - } + tenantId: request.body.CampaignDetails.tenantId, + }, + ], + }; const params = { tenantId: request.body.CampaignDetails.tenantId, offset: 0, - limit: 5 - } + limit: 5, + }; var projectFound = false; var retry = 6; while (!projectFound && retry >= 0) { - const response = await httpRequest(config.host.projectHost + config.paths.projectSearch, searchBody, params); + const response = await httpRequest( + config.host.projectHost + config.paths.projectSearch, + searchBody, + params + ); if (response?.Project?.[0]) { projectFound = true; - } - else { + } else { logger.info("Project not found. Waiting for 1 seconds"); - retry = retry - 1 + retry = retry - 1; logger.info(`Waiting for ${retry} for 1 more second`); - await new Promise(resolve => setTimeout(resolve, 1000)); + await new Promise((resolve) => setTimeout(resolve, 1000)); } } if (!projectFound) { - throwError("PROJECT", 500, "PROJECT_CONFIRMATION_FAILED", "Project confirmation failed, for the project with id " + projectId); + 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 API started") - logger.debug("Project creation body " + getFormattedStringForDebug(projectCreateBody)) - const projectCreateResponse = await httpRequest(config.host.projectHost + config.paths.projectCreate, projectCreateBody, undefined, undefined, undefined, undefined, undefined, true); - logger.debug("Project creation response" + getFormattedStringForDebug(projectCreateResponse)) + logger.info("Project creation API started"); + logger.debug( + "Project creation body " + getFormattedStringForDebug(projectCreateBody) + ); + if (!request.body.newlyCreatedBoundaryProjectMap) { + request.body.newlyCreatedBoundaryProjectMap = {}; + } + const projectCreateResponse = await httpRequest( + config.host.projectHost + config.paths.projectCreate, + projectCreateBody, + undefined, + undefined, + undefined, + undefined, + undefined, + true + ); + logger.debug( + "Project creation response" + + getFormattedStringForDebug(projectCreateResponse) + ); if (projectCreateResponse?.Project[0]?.id) { - logger.info("Project created successfully with name " + JSON.stringify(projectCreateResponse?.Project[0]?.name)) - 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 + logger.info( + "Project created successfully with name " + + JSON.stringify(projectCreateResponse?.Project[0]?.name) + ); + logger.info( + `for boundary type ${projectCreateResponse?.Project[0]?.address?.boundaryType} and code ${projectCreateResponse?.Project[0]?.address?.boundary}` + ); + // if ( + // !request.body.newlyCreatedBoundaryProjectMap[ + // projectCreateBody?.Projects?.[0]?.address?.boundary + // ] + // ) { + // request.body.newlyCreatedBoundaryProjectMap[ + // projectCreateBody?.Projects?.[0]?.address?.boundary + // ] = {}; + // } + request.body.boundaryProjectMapping[ + projectCreateBody?.Projects?.[0]?.address?.boundary + ].projectId = projectCreateResponse?.Project[0]?.id; + // request.body.newlyCreatedBoundaryProjectMap[ + // 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) + ); } - else { - throwError("PROJECT", 500, "PROJECT_CREATION_FAILED", "Project creation failed, for the request: " + JSON.stringify(projectCreateBody)); +} + +async function projectUpdateForTargets(projectUpdateBody: any, request: any, boundaryCode: any) { + logger.info("Project Update For Targets started"); + + logger.debug("Project update request body: " + getFormattedStringForDebug(projectUpdateBody)); + logger.info(`Project update started for boundary code: ${boundaryCode} and project name: ${request?.body?.CampaignDetails?.campaignName}`); + + try { + const projectUpdateResponse = await httpRequest( + config.host.projectHost + config.paths.projectUpdate, + projectUpdateBody, + undefined, undefined, undefined, undefined, undefined, + true + ); + logger.debug("Project update response: " + getFormattedStringForDebug(projectUpdateResponse)); + logger.info(`Project update response for boundary code: ${boundaryCode} and project name: ${request?.body?.CampaignDetails?.campaignName}`); + } catch (error: any) { + logger.error("Project update failed", error); + throwError( + "PROJECT", + 500, + "PROJECT_UPDATE_ERROR", + `Project update failed for the request: ${getFormattedStringForDebug(projectUpdateBody)}. Error: ${getFormattedStringForDebug(error.message)}` + ); } } @@ -929,7 +1909,7 @@ function generateHierarchyList(data: any[], parentChain: any = []) { let currentChain = [...parentChain, boundary.code]; // Add the current chain to the result - result.push(currentChain.join(',')); + result.push(currentChain.join(",")); // If there are children, recursively call the function if (boundary.children && boundary.children.length > 0) { @@ -938,52 +1918,69 @@ function generateHierarchyList(data: any[], parentChain: any = []) { } } 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 getHierarchy = async ( + request: any, + tenantId: string, + hierarchyType: string +) => { + const BoundaryTypeHierarchySearchCriteria: BoundaryModels.BoundaryHierarchyDefinitionSearchCriteria = + { + BoundaryTypeHierarchySearchCriteria: { + tenantId, + hierarchyType, + }, }; - - const response = await httpRequest(url, requestBody); + const response: BoundaryModels.BoundaryHierarchyDefinitionResponse = + await searchBoundaryRelationshipDefinition( + BoundaryTypeHierarchySearchCriteria + ); 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 getExcelWorkbookFromFileURL(fileUrl, localizedBoundarySheetName); +const getHeadersOfBoundarySheet = async ( + fileUrl: string, + sheetName: string, + getRow = false, + localizationMap?: any +) => { + const localizedBoundarySheetName = getLocalizedName( + sheetName, + localizationMap + ); + const workbook: any = await getExcelWorkbookFromFileURL( + fileUrl, + localizedBoundarySheetName + ); const worksheet = workbook.getWorksheet(localizedBoundarySheetName); - const columnsToValidate = worksheet.getRow(1).values.map((header: any) => header ? header.toString().trim() : undefined); + const columnsToValidate = worksheet + .getRow(1) + .values.map((header: any) => + header ? header.toString().trim() : undefined + ); // Filter out empty items and return the result - return columnsToValidate.filter((header: any) => typeof header === 'string'); -} - + return columnsToValidate.filter((header: any) => typeof header === "string"); +}; async function getCampaignSearchResponse(request: any) { try { logger.info(`searching for campaign details`); - const requestInfo = { "RequestInfo": request?.body?.RequestInfo }; - const campaignDetails = { "CampaignDetails": { tenantId: request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, "ids": [request?.query?.campaignId || request?.body?.ResourceDetails?.campaignId] } } - const requestBody = { ...requestInfo, ...campaignDetails }; - const req: any = replicateRequest(request, requestBody) - const projectTypeSearchResponse: any = await searchProjectTypeCampaignService(req); +const CampaignDetails = { + tenantId: request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, + ids: [request?.query?.campaignId || request?.body?.ResourceDetails?.campaignId], +}; + const projectTypeSearchResponse: any = + await searchProjectTypeCampaignService(CampaignDetails); return projectTypeSearchResponse; } catch (error: any) { - logger.error(`Error while searching for campaign details: ${error.message}`); - throwError("COMMON", 400, "RESPONSE_NOT_FOUND_ERROR", error?.message) + logger.error( + `Error while searching for campaign details: ${error.message}` + ); + throwError("COMMON", 400, "RESPONSE_NOT_FOUND_ERROR", error?.message); } } @@ -1003,5 +2000,6 @@ export { getHeadersOfBoundarySheet, handleResouceDetailsError, getCampaignSearchResponse, - confirmProjectParentCreation + confirmProjectParentCreation, + projectUpdateForTargets }; diff --git a/health-services/project-factory/src/server/api/coreApis.ts b/health-services/project-factory/src/server/api/coreApis.ts new file mode 100644 index 00000000000..aa9ba13003c --- /dev/null +++ b/health-services/project-factory/src/server/api/coreApis.ts @@ -0,0 +1,259 @@ +// Import necessary types and utilities +import { BoundaryModels, MDMSModels } from "../models"; +import config from "../config"; +import { httpRequest } from "../utils/request"; + +// Default request information for MDMS API requests +export const defaultRequestInfo: any = { + RequestInfo: { + apiId: "PROJECTFACTORY", // Identifier for the calling application, + msgId: `${new Date().getTime()}|${config.localisation.defaultLocale}`, + ...(config.isProduction && config.token && { authToken :config.token}), + ...{ userInfo:{ + tenantId:config?.app?.defaultTenantId + }}, + }, +}; + +/** + * Searches MDMS data via the v2 API for specific unique identifiers. + * + * @author jagankumar-egov + * + * @param MdmsCriteria - The criteria for the MDMS v2 search, including tenantId and schemaCode. + * @returns Promise resolving to the MDMS v2 search response containing matched data. + */ +const searchMDMSDataViaV2Api = async ( + MdmsCriteria: MDMSModels.MDMSv2RequestCriteria +): Promise => { + // Construct the full API URL for the v2 MDMS search + const apiUrl: string = config.host.mdmsV2 + config.paths.mdms_v2_search; + + // Prepare the data payload for the API request + const data = { + MdmsCriteria, + ...defaultRequestInfo, + }; + + // Make an HTTP request to the MDMS v2 API + const response: MDMSModels.MDMSv2Response = await httpRequest(apiUrl, data); + + // Return the response from the API + return response; +}; + +/** + * Fetches the schema definitions from MDMS based on specified criteria. + * + * @author jagankumar-egov + * + * @param SchemaDefCriteria - The criteria for fetching schema definitions, including tenantId and limit. + * @returns Promise resolving to the response containing schema definitions. + */ +const searchMDMSSchema = async ( + SchemaDefCriteria: MDMSModels.MDMSSchemaRequestCriteria +): Promise => { + // Construct the request body including schema criteria and default request info + const requestBody = { + ...SchemaDefCriteria, + ...defaultRequestInfo, + }; + + // Define the API URL for schema retrieval + const url = config.host.mdmsV2 + config.paths.mdmsSchema; + + // Make an HTTP request with a tenant ID in headers + const response: MDMSModels.MDMSSchemaResponse = await httpRequest( + url, + requestBody, + { tenantId: SchemaDefCriteria?.SchemaDefCriteria?.tenantId } + ); + + // Return the schema definitions from the response + return response; +}; + +/** + * Searches MDMS data via the v1 API using given criteria. + * + * @author jagankumar-egov + * + * @param MdmsCriteria - The criteria for the MDMS v1 search, including tenantId and moduleDetails. + * @returns Promise resolving to the MDMS v1 search response. + */ +const searchMDMSDataViaV1Api = async ( + MdmsCriteria: MDMSModels.MDMSv1RequestCriteria +): Promise => { + // Construct the request body with v1 search criteria and default request info + const requestBody = { + ...MdmsCriteria, + ...defaultRequestInfo, + }; + + // Define the API URL for MDMS v1 search + const url = config.host.mdmsV2 + config.paths.mdms_v1_search; + + // Make an HTTP request with tenant ID in headers + const response: MDMSModels.MDMSv1Response = await httpRequest( + url, + requestBody, + { tenantId: MdmsCriteria.MdmsCriteria.tenantId } + ); + + // Return the search result from MDMS v1 + return response; +}; + + +/** + * Searches boundary entities in the MDMS system using specified criteria. + * + * @author jagankumar-egov + * + * @function searchBoundaryEntity + * @param tenantId - Unique identifier for the tenant. + * @param codes - Specific codes to filter the boundary entities. + * @param limit - Maximum number of results to return (default is 100). + * @param offset - Starting position for fetching results (default is 0). + * @returns Promise resolving to the boundary entity search response. + * + * @remarks + * This function constructs and sends a request to the boundary entity service, + * using the provided criteria to filter and retrieve specific boundary entities. + * Additional headers contain tenant ID, offset, limit, and codes for filtering. + * + * @example + * const response = await searchBoundaryEntity("mz", "MOZ", 50, 0); + */ +const searchBoundaryEntity = async ( + tenantId: string, + codes: string, + limit: number = 100, + offset: number = 0, +): Promise => { + // Prepare request body with default request information + const requestBody = { + ...defaultRequestInfo, + }; + + // Construct API URL for boundary entity search + const url = config.host.boundaryHost + config.paths.boundaryServiceSearch; + + // Execute HTTP request with tenant ID, offset, limit, and codes in headers + const response: BoundaryModels.BoundaryEntityResponse = await httpRequest( + url, + requestBody, + { tenantId, offset, limit, codes } + ); + + // Return the response containing boundary entity data + return response; +}; + +/** + * Searches boundary hierarchy relationship data within the MDMS system. + * + * @author jagankumar-egov + * + * @function searchBoundaryRelationshipData + * @param tenantId - Unique identifier for the tenant. + * @param hierarchyType - Type of hierarchy to search within. + * @param includeChildren - Whether to include child relationships (default is true). + * @param includeParents - Whether to include parent relationships (default is true). + * @returns Promise resolving to the boundary hierarchy relationship response. + * + * @remarks + * This function queries the boundary relationship API to retrieve hierarchy data + * based on the specified hierarchy type and inclusion of child or parent entities. + * + * @example + * const response = await searchBoundaryRelationshipData("mz", "ADMIN", true, false); + */ +const searchBoundaryRelationshipData = async ( + tenantId: string, + hierarchyType: string, + includeChildren: boolean = true, + includeParents: boolean = true, +): Promise => { + // Prepare request body with default request information + const requestBody = { + ...defaultRequestInfo, + }; + + // Construct API URL for boundary hierarchy relationship search + const url = config.host.boundaryHost + config.paths.boundaryRelationship; + + // Execute HTTP request with tenant ID, hierarchy type, and inclusion flags in headers + const response: BoundaryModels.BoundaryHierarchyRelationshipResponse = await httpRequest( + url, + requestBody, + { tenantId, hierarchyType, includeChildren, includeParents } + ); + + // Return the response containing boundary relationship data + return response; +}; + +/** + * Searches boundary hierarchy definitions based on provided search criteria. + * + * @author jagankumar-egov + * + * @function searchBoundaryRelationshipDefinition + * @param BoundaryTypeHierarchySearchCriteria - Criteria for fetching boundary hierarchy definitions. + * @returns Promise resolving to the boundary hierarchy definition response. + * + * @remarks + * This function sends a request to retrieve hierarchy definitions for boundary types, + * based on specified criteria such as tenant ID and hierarchy parameters. + * + * @example + * const criteria = { tenantId: "mz", hierarchyCode: "ADMIN" }; + * const response = await searchBoundaryRelationshipDefinition(criteria); + */ +const searchBoundaryRelationshipDefinition = async ( + BoundaryTypeHierarchySearchCriteria: BoundaryModels.BoundaryHierarchyDefinitionSearchCriteria +): Promise => { + // Prepare request body with search criteria and default request information + const requestBody = { + ...BoundaryTypeHierarchySearchCriteria, + ...defaultRequestInfo, + }; + + // Construct API URL for boundary hierarchy definition search + const url = config.host.boundaryHost + config.paths.boundaryHierarchy; + + // Execute HTTP request to fetch boundary hierarchy definitions + const response: BoundaryModels.BoundaryHierarchyDefinitionResponse = await httpRequest( + url, + requestBody, + ); + + // Return the response containing hierarchy definition data + return response; +}; + + + +const fetchFileFromFilestore=async(filestoreId:string,tenantId:string)=> { + + try { + const reqParamsForFetchingFile = { + tenantId: tenantId, + fileStoreIds: filestoreId + }; + const fileResponse= await httpRequest( + `${config?.host?.filestore}${config?.paths?.filestorefetch}`, + {}, + reqParamsForFetchingFile, + "get" + ); + return fileResponse?.fileStoreIds?.[0].url; + } catch (error) { + console.error("Error fetching file URLs:", error); + throw error; + } +} + +// Exporting all API functions for MDMS operations +export { searchMDMSDataViaV2Api, searchMDMSSchema, searchMDMSDataViaV1Api ,searchBoundaryEntity, searchBoundaryRelationshipData, searchBoundaryRelationshipDefinition ,fetchFileFromFilestore}; diff --git a/health-services/project-factory/src/server/api/genericApis.ts b/health-services/project-factory/src/server/api/genericApis.ts index 3325efc9d73..2ae5f0f7491 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); } @@ -61,34 +60,49 @@ function getJsonData(sheetData: any, getRow = false, getSheetName = false, sheet return jsonData; } -function validateFirstRowColumn(createAndSearchConfig: any, worksheet: any, localizationMap: any) { - if ( - createAndSearchConfig && - createAndSearchConfig.parseArrayConfig && - createAndSearchConfig.parseArrayConfig.parseLogic - ) { - const parseLogic = createAndSearchConfig.parseArrayConfig.parseLogic; - // Iterate over each column configuration - for (const columnConfig of parseLogic) { - const { sheetColumn, sheetColumnName } = columnConfig; - const localizedColumnName = getLocalizedName(sheetColumnName, localizationMap); - - // Get the value of the first row in the current column - if (sheetColumn && localizedColumnName) { - const firstRowValue = worksheet.getCell(sheetColumn + '1').value; - - // 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}.` - ); - } - } +// function validateFirstRowColumn(createAndSearchConfig: any, worksheet: any, localizationMap: any) { +// if (createAndSearchConfig?.parseArrayConfig?.parseLogic) { +// const parseLogic = createAndSearchConfig.parseArrayConfig.parseLogic; +// // Iterate over each column configuration +// for (const columnConfig of parseLogic) { +// const { sheetColumn, sheetColumnName } = columnConfig; +// const localizedColumnName = getLocalizedName(sheetColumnName, localizationMap); + +// // Get the value of the first row in the current column +// if (sheetColumn && localizedColumnName) { +// const firstRowValue = worksheet.getCell(sheetColumn + '1').value; + +// // 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}.` +// ); +// } +// } +// } +// } +// } + +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 @@ -99,19 +113,57 @@ 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); + // 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 ('hyperlink' in cell.value) { + if (cell?.value?.text?.richText?.length > 0) { + return cell.value.text.richText.map((t: any) => t.text).join(''); + } + else { + return cell.value.text; + } + } + else if ('formula' in cell.value) { + // Get the result of the formula + return cell.value.result; + } + else if ('sharedFormula' in cell.value) { + // Get the result of the shared 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,13 +183,14 @@ 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; }; const getTargetSheetDataAfterCode = async ( + request: any, fileUrl: string, getRow = false, getSheetName = false, @@ -155,40 +208,58 @@ 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]; - let targetColumnIndex = -1; + const firstRow = sheetData[0]; + let boundaryCodeColumnIndex = -1; for (let colIndex = 1; colIndex < firstRow.length; colIndex++) { if (firstRow[colIndex] === codeColumnName) { - targetColumnIndex = colIndex; + boundaryCodeColumnIndex = colIndex; break; } } - if (targetColumnIndex === -1) { + if (boundaryCodeColumnIndex === -1) { console.warn(`Column "${codeColumnName}" not found in sheet "${sheetName}".`); continue; } // Process data from sheet const processedData = sheetData.map((row: any, rowIndex: any) => { - if (rowIndex <= 1) return null; // Skip header row + if (rowIndex <= 0) return null; // Skip header row - let rowData: any = { [codeColumnName]: row[targetColumnIndex] }; + let rowData: any = { [codeColumnName]: row[boundaryCodeColumnIndex] }; // Add integer values in the target column for the current row - let sum = 0; - for (let colIndex = targetColumnIndex + 1; colIndex < row.length; colIndex++) { + let sumOfCurrentTargets = 0; + let sumOfParentTargets = 0; + const remainingColumns = row.length - boundaryCodeColumnIndex - 1; + const halfPoint = Math.floor(remainingColumns / 2); + let startColIndex = boundaryCodeColumnIndex + 1; + + if (request?.body?.parentCampaign) { + for (let colIndex = startColIndex; colIndex < startColIndex + halfPoint; colIndex++) { + const value = row[colIndex]; + if (typeof value === 'number' && Number.isInteger(value)) { + sumOfParentTargets += value; + } + } + // Add the sum to the row data + rowData['Parent Target at the Selected Boundary level'] = sumOfParentTargets; + + // Calculate middle point of remaining columns + startColIndex = boundaryCodeColumnIndex + 1 + halfPoint; + } + for (let colIndex = startColIndex; colIndex < row.length; colIndex++) { const value = row[colIndex]; if (typeof value === 'number' && Number.isInteger(value)) { - sum += value; + sumOfCurrentTargets += value; } } // Add the sum to the row data - rowData['Target at the Selected Boundary level'] = sum; + rowData['Target at the Selected Boundary level'] = sumOfCurrentTargets; return rowData; }).filter(Boolean); // Remove null entries @@ -211,7 +282,7 @@ const searchMDMS: any = async ( } // Construct API URL for MDMS search - const apiUrl = config.host.mdms + config.paths.mdms_search; + const apiUrl = config.host.mdmsV2 + config.paths.mdms_v2_search; // Construct request data for MDMS search const data = { @@ -338,7 +409,7 @@ const getSchema: any = async (code: string, RequestInfo: any) => { codes: [code], }, }; - const mdmsSearchUrl = config.host.mdms + config.paths.mdmsSchema; + const mdmsSearchUrl = config.host.mdmsV2 + config.paths.mdmsSchema; try { const result = await httpRequest( @@ -397,12 +468,62 @@ async function createAndUploadFile( request: any, tenantId?: any ) { - // Write the updated workbook to a buffer - const buffer = await updatedWorkbook.xlsx.writeBuffer(); + let retries: any = 3; + while (retries--) { + try { + // Write the updated workbook to a buffer + const buffer = await updatedWorkbook.xlsx.writeBuffer(); + + // 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 || request?.RequestInfo?.authToken, + } + ); + + // Extract response data + const responseData = fileCreationResult?.files; + if (responseData) { + return responseData; + } + } + catch (error: any) { + console.error(`Attempt failed:`, error.message); + + // Add a delay before the next retry (2 seconds) + await new Promise((resolve) => setTimeout(resolve, 5000)); + } + } + throw new Error("Error while uploading excel file: INTERNAL_SERVER_ERROR"); +} + +async function createAndUploadJsonFile( + jsonData: any, // Expecting JSON data as an argument + request: any, + tenantId?: any +) { + // Convert JSON data to a string + const jsonString = JSON.stringify(jsonData); + const buffer = Buffer.from(jsonString); // Create form data for file upload const formData = new FormData(); - formData.append("file", buffer, "filename.xlsx"); + formData.append("file", buffer, { filename: "filename.json", contentType: "application/json" }); formData.append( "tenantId", tenantId ? tenantId : request?.body?.RequestInfo?.userInfo?.tenantId @@ -426,13 +547,14 @@ async function createAndUploadFile( const responseData = fileCreationResult?.files; if (!responseData) { throw new Error( - "Error while uploading excel file: INTERNAL_SERVER_ERROR" + "Error while uploading JSON file: INTERNAL_SERVER_ERROR" ); } return responseData; // Return the response data } + // Function to generate a list of hierarchy codes function generateHierarchyList(data: any[], parentChain: any = []) { let result: any[] = []; @@ -544,51 +666,95 @@ async function getAutoGeneratedBoundaryCodes(boundaryList: any, childParentMap: 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); - } + if (!findMapValue(elementCodesMap, element) && 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; } } } + modifyElementCodesMap(elementCodesMap); // Modify the element codes map return elementCodesMap; // Return the updated element codes map } +function modifyElementCodesMap(elementCodesMap: any) { + const set = new Set(); + const specialCharsRegex = /[^\w]/g; // Regular expression to match any character that is not a word character + + // Iterate over each [key, value] pair in elementCodesMap using forEach + elementCodesMap.forEach((value: any, key: any) => { + let modifiedValue = value.replace(specialCharsRegex, '_').trim(); // Replace special characters and spaces with underscore + let modifiedTempValue = modifiedValue; // Store the initial modified value + let count = 1; + + // Generate a unique modified value + while (set.has(modifiedValue)) { + // If it exists, append _ to modifiedValue + modifiedValue = `${modifiedTempValue}_${count}`; + count++; + } + + // Add the modified (or original) value to the set + set.add(modifiedValue); + + // Update the map with the modified value + elementCodesMap.set(key, modifiedValue); + }); + +} + /** * 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(); } /** @@ -624,7 +790,14 @@ async function getBoundarySheetData( modifiedHierarchy, localizationMap ); - const headerColumnsAfterHierarchy = await getConfigurableColumnHeadersBasedOnCampaignType(request, localizationMap); + var headerColumnsAfterHierarchy; + if (request?.query?.type != "boundaryManagement" && request?.query?.type !== 'boundaryGeometryManagement') { + headerColumnsAfterHierarchy = await getConfigurableColumnHeadersBasedOnCampaignType(request, localizationMap); + } + + if (request?.query?.type === "boundaryManagement" || request?.query?.type === 'boundaryGeometryManagement') { + headerColumnsAfterHierarchy = await getConfigurableColumnHeadersBasedOnCampaignTypeForBoundaryManagement(request, localizationMap); + } const headers = [...localizedHeadersUptoHierarchy, ...headerColumnsAfterHierarchy]; // create empty sheet if no boundary present in system // const localizedBoundaryTab = getLocalizedName( @@ -637,26 +810,100 @@ 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 if (request?.query?.type !== "boundaryManagement") { + // logger.info("boundaryData for sheet " + JSON.stringify(boundaryData)) + const responseFromCampaignSearch = + await getCampaignSearchResponse(request); + Filters = await getFiltersFromCampaignSearchResponse(request, 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); } } } +async function getConfigurableColumnHeadersBasedOnCampaignTypeForBoundaryManagement(request: any, localizationMap?: { [key: string]: string }) { + try { + const mdmsResponse = await callMdmsTypeSchema( + request, + request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, + false, + request?.query?.type || request?.body?.ResourceDetails?.type, + "all" + ); + if (!mdmsResponse || mdmsResponse?.columns.length === 0) { + logger.error( + `Campaign Type all has not any columns configured in schema` + ); + throwError( + "COMMON", + 400, + "SCHEMA_ERROR", + `Campaign Type all has not any columns configured in schema` + ); + } + // Extract columns from the response + const columnsForGivenCampaignId = mdmsResponse?.columns; + + // Get localized headers based on the column names + const headerColumnsAfterHierarchy = getLocalizedHeaders( + columnsForGivenCampaignId, + localizationMap + ); + if ( + !headerColumnsAfterHierarchy.includes( + getLocalizedName(config.boundary.boundaryCode, localizationMap) + ) + ) { + logger.error( + `Column Headers of generated Boundary Template does not have ${getLocalizedName( + config.boundary.boundaryCode, + localizationMap + )} column` + ); + throwError( + "COMMON", + 400, + "VALIDATION_ERROR", + `Column Headers of generated Boundary Template does not have ${getLocalizedName( + config.boundary.boundaryCode, + localizationMap + )} column` + ); + } + return headerColumnsAfterHierarchy; + } catch (error: any) { + console.log(error); + throwError( + "FILE", + 400, + "FETCHING_COLUMN_ERROR", + "Error fetching column Headers From Schema (either boundary code column not found or given Campaign Type not found in schema) Check logs" + ); + } +} async function createStaff(resouceBody: any) { // Create staff const staffCreateUrl = @@ -671,8 +918,7 @@ async function createStaff(resouceBody: any) { undefined, undefined, undefined, - false, - true + false ); logger.info("Project Staff mapping created"); logger.debug( @@ -700,8 +946,7 @@ async function createProjectResource(resouceBody: any) { undefined, undefined, undefined, - false, - true + false ); logger.debug("Project Resource Created"); logger.debug( @@ -729,8 +974,7 @@ async function createProjectFacility(resouceBody: any) { undefined, undefined, undefined, - false, - true + false ); logger.info("Project Facility Created"); logger.debug( @@ -741,44 +985,63 @@ async function createProjectFacility(resouceBody: any) { } // Helper function to create staff -const createStaffHelper = (resourceId: any, projectId: any, resouceBody: any, tenantId: any, startDate: any, endDate: any) => { - const ProjectStaff = { - tenantId: tenantId.split(".")?.[0], - projectId, - userId: resourceId, - startDate, - endDate, - }; - const newResourceBody = { ...resouceBody, ProjectStaff }; - return createStaff(newResourceBody); +const createProjectStaffHelper = (resourceId: any, projectId: any, resouceBody: any, tenantId: any, startDate: any, endDate: any) => { + try { + const ProjectStaff = { + tenantId: tenantId.split(".")?.[0], + projectId, + userId: resourceId, + startDate, + endDate, + }; + const newResourceBody = { ...resouceBody, ProjectStaff }; + return createStaff(newResourceBody); + } catch (error) { + // Log the error if the API call fails + logger.error(`Failed to create project staff for staffId ${resourceId}:`, error); + throw error; // Rethrow the error to propagate it + } }; // Helper function to create project resource const createProjectResourceHelper = (resourceId: any, projectId: any, resouceBody: any, tenantId: any, startDate: any, endDate: any) => { - const ProjectResource = { - tenantId: tenantId.split(".")?.[0], - projectId, - resource: { - productVariantId: resourceId, - type: "DRUG", - isBaseUnitVariant: false, - }, - startDate, - endDate, - }; - const newResourceBody = { ...resouceBody, ProjectResource }; - return createProjectResource(newResourceBody); + try { + const ProjectResource = { + tenantId: tenantId.split(".")?.[0], + projectId, + resource: { + productVariantId: resourceId, + type: "DRUG", + isBaseUnitVariant: false, + }, + startDate, + endDate, + }; + const newResourceBody = { ...resouceBody, ProjectResource }; + return createProjectResource(newResourceBody); + } + catch (error) { + // Log the error if the API call fails + logger.error(`Failed to create project resource for resourceId ${resourceId}:`, error); + throw error; // Rethrow the error to propagate it + } }; // Helper function to create project facility -const createProjectFacilityHelper = (resourceId: any, projectId: any, resouceBody: any, tenantId: any) => { - const ProjectFacility = { - tenantId: tenantId.split(".")?.[0], - projectId, - facilityId: resourceId, - }; - const newResourceBody = { ...resouceBody, ProjectFacility }; - return createProjectFacility(newResourceBody); +const createProjectFacilityHelper = (resourceId: any, projectId: any, resouceBody: any, tenantId: any, startDate: any, endDate: any) => { + try { + const ProjectFacility = { + tenantId: tenantId.split(".")?.[0], + projectId, + facilityId: resourceId, + }; + const newResourceBody = { ...resouceBody, ProjectFacility }; + return createProjectFacility(newResourceBody); + } catch (error) { + // Log the error if the API call fails + logger.error(`Failed to create facility for facilityId ${resourceId}:`, error); + throw error; // Rethrow the error to propagate it + } }; @@ -792,32 +1055,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, parentCampaign: requestBody?.parentCampaign } + await processMapping(mappingObject) } @@ -827,32 +1089,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 + ); } /** @@ -932,7 +1196,7 @@ async function confirmBoundaryParentCreation(request: any, code: any) { var boundaryFound = false; const header = { ...defaultheader, - cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, + // cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes.replace(/’/g, '') || ''}${params?.includeChildren || ''}`, } while (!boundaryFound && retry >= 0) { const response = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, searchBody, params, undefined, undefined, header); @@ -975,7 +1239,7 @@ async function createBoundaryRelationship(request: any, boundaryMap: Map<{ key: }; const header = { ...defaultheader, - cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, + // cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, } const boundaryRelationshipResponse = await httpRequest(url, request.body, params, undefined, undefined, header); @@ -1006,7 +1270,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); @@ -1056,12 +1320,12 @@ async function callMdmsData( ], }, }; - const url = config.host.mdms + config.paths.mdms_v1_search; + const url = config.host.mdmsV2 + config.paths.mdms_v1_search; const response = await httpRequest(url, requestBody, { tenantId: tenantId }); return response; } -function enrichSchema(data: any, properties: any, required: any, columns: any, unique: any, columnsNotToBeFreezed: any, errorMessage: any) { +function enrichSchema(data: any, properties: any, required: any, columns: any, unique: any, columnsNotToBeFreezed: any, columnsToBeFreezed: any, columnsToHide: any, errorMessage: any) { // Sort columns based on orderNumber, using name as tie-breaker if orderNumbers are equal columns.sort((a: any, b: any) => { @@ -1090,15 +1354,19 @@ function enrichSchema(data: any, properties: any, required: any, columns: any, u data.unique = unique; data.errorMessage = errorMessage; data.columnsNotToBeFreezed = columnsNotToBeFreezed; + data.columnsToBeFreezed = columnsToBeFreezed; + data.columnsToHide = columnsToHide; } -function convertIntoSchema(data: any) { +function convertIntoSchema(data: any, isUpdate: boolean) { const properties: any = {}; const errorMessage: any = {}; const required: any[] = []; - const columns: any[] = []; + let columns: any[] = []; const unique: any[] = []; const columnsNotToBeFreezed: any[] = []; + const columnsToBeFreezed: any[] = []; + const columnsToHide: any[] = []; for (const propType of ['enumProperties', 'numberProperties', 'stringProperties']) { if (data.properties[propType] && Array.isArray(data.properties[propType]) && data.properties[propType]?.length > 0) { @@ -1119,13 +1387,40 @@ function convertIntoSchema(data: any) { if (!property?.freezeColumn || property?.freezeColumn == false) { columnsNotToBeFreezed.push(property?.name); } + if (property?.freezeColumn) { + columnsToBeFreezed.push(property?.name); + } + if (property?.hideColumn) { + columnsToHide.push(property?.name); + } // If orderNumber is missing, default to a very high number - columns.push({ name: property?.name, orderNumber: property?.orderNumber || 9999999999 }); + if (isUpdate) { + columns.push({ name: property?.name, orderNumber: property?.orderNumber || 9999999999 }); + } + else { + if (!property?.isUpdate) { + columns.push({ name: property?.name, orderNumber: property?.orderNumber || 9999999999 }); + } + } } } } - enrichSchema(data, properties, required, columns, unique, columnsNotToBeFreezed, errorMessage); + + const descriptionToFieldMap: Record = {}; + + for (const [key, field] of Object.entries(properties)) { + // Cast field to `any` since it is of type `unknown` + const typedField = field as any; + + if (typedField.isRequired) { + descriptionToFieldMap[typedField.description] = key; + } + } + data.descriptionToFieldMap = descriptionToFieldMap; + + + enrichSchema(data, properties, required, columns, unique, columnsNotToBeFreezed, columnsToBeFreezed, columnsToHide, errorMessage); return data; } @@ -1134,6 +1429,7 @@ function convertIntoSchema(data: any) { async function callMdmsTypeSchema( request: any, tenantId: string, + isUpdate: boolean, type: any, campaignType = "all" ) { @@ -1157,7 +1453,7 @@ async function callMdmsTypeSchema( if (!response?.mdms?.[0]?.data) { throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Error occured during schema search"); } - return convertIntoSchema(response?.mdms?.[0]?.data); + return convertIntoSchema(response?.mdms?.[0]?.data, isUpdate); } async function getMDMSV1Data(request: any, moduleName: string, masterName: string, tenantId: string) { @@ -1187,5 +1483,10 @@ export { getTargetSheetDataAfterCode, callMdmsData, getMDMSV1Data, - callMdmsTypeSchema -} + callMdmsTypeSchema, + getSheetDataFromWorksheet, + createProjectStaffHelper, + createProjectFacilityHelper, createProjectResourceHelper, + createAndUploadJsonFile, + getConfigurableColumnHeadersBasedOnCampaignTypeForBoundaryManagement +}; diff --git a/health-services/project-factory/src/server/api/healthApis.ts b/health-services/project-factory/src/server/api/healthApis.ts new file mode 100644 index 00000000000..0a2b0c8b0de --- /dev/null +++ b/health-services/project-factory/src/server/api/healthApis.ts @@ -0,0 +1,28 @@ +import { httpRequest } from "../utils/request"; +import { defaultRequestInfo } from "./coreApis"; +import config from "../config"; +import { throwError } from "../utils/genericUtils"; +import { logger } from "../utils/logger"; + +export async function fetchProductVariants(pvarIds: string[]) { + const CHUNK_SIZE = 100; + const allProductVariants: any[] = []; + const params: any = { limit: CHUNK_SIZE, offset: 0, tenantId: defaultRequestInfo?.RequestInfo?.userInfo?.tenantId }; + + for (let i = 0; i < pvarIds.length; i += CHUNK_SIZE) { + const chunk = pvarIds.slice(i, i + CHUNK_SIZE); + try { + const response = await httpRequest( + config.host.productHost + config.paths.productVariantSearch, + { ProductVariant: { id: chunk }, ...defaultRequestInfo }, + params + ); + allProductVariants.push(...response?.ProductVariant || []); + } catch (error: any) { + logger.error("Error during product variant fetch"); + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", `Some error occurred while fetching product variants. ${error?.message}`); + } + } + + return allProductVariants; // Return the fetched product variants +} diff --git a/health-services/project-factory/src/server/api/microplanApis.ts b/health-services/project-factory/src/server/api/microplanApis.ts new file mode 100644 index 00000000000..0dc0bcb97eb --- /dev/null +++ b/health-services/project-factory/src/server/api/microplanApis.ts @@ -0,0 +1,124 @@ +import config from "../config"; // Import configuration settings +import { httpRequest } from "../utils/request"; // Import httpRequest function for making HTTP requests +import { logger } from "../utils/logger"; // Import logger for logging information and errors +import { defaultRequestInfo } from "./coreApis"; // Import default request information + +/** + * Searches for facilities associated with a specific plan configuration. + * @param planConfigId The unique identifier for the plan configuration. + * @param tenantId The tenant identifier for which the search is performed. + * @returns The response containing facility details for the specified plan configuration. + */ +export const searchPlanFacility = async ( + planConfigId: string, + tenantId: string +) => { + const searchBody = { + PlanFacilitySearchCriteria: { + tenantId: tenantId, + planConfigurationId: planConfigId, + }, + ...defaultRequestInfo, // Include default request metadata + }; + logger.info( + `Received a search request for plan facility with ID: ${planConfigId}` + ); + const planFacilityResponse = await httpRequest( + config.host.planServiceHost + config.paths.planFacilitySearch, // Construct the request URL + searchBody // Pass the request body + ); + return planFacilityResponse?.PlanFacility; // Return the response from the facility search +}; + +/** + * Searches for plans based on configuration, tenant, and boundaries. + * @param planConfigId The unique identifier for the plan configuration. + * @param tenantId The tenant identifier for which the search is performed. + * @param boundaries The jurisdiction or boundary information for the search. + * @returns The response containing plan details for the specified criteria. + */ +export const searchPlan = async ( + planConfigId: string, + tenantId: string, + limit:number=1 +) => { + const searchBody = { + PlanSearchCriteria: { + tenantId: tenantId, + active: true, // Search only active plans + // jurisdiction: boundaries, // Specify jurisdiction for the search + planConfigurationId: planConfigId, + limit: limit, // Limit the response to 1 result + offset: 0, // Start from the first result + }, + ...defaultRequestInfo, // Include default request metadata + }; + logger.info( + `Received a search request for plans with ID: ${planConfigId}` + ); + const planResponse = await httpRequest( + config.host.planServiceHost + config.paths.planSearch, // Construct the request URL + searchBody // Pass the request body + ); + return planResponse?.Plan; // Return the response from the plan search +}; + +/** + * Searches for census data related to a specific plan configuration and boundary codes. + * @param planConfigId The unique identifier for the plan configuration. + * @param tenantId The tenant identifier for which the search is performed. + * @param boundaryCodes The area codes defining the search boundaries. + * @returns The response containing census details for the specified criteria. + */ +export const searchPlanCensus = async ( + planConfigId: string, + tenantId: string, + limit:number=1 +) => { + const searchBody = { + CensusSearchCriteria: { + tenantId: tenantId, + source: planConfigId, // Use planConfigId as the source of the census data + // areaCodes: boundaryCodes, // Specify area codes for the search + offset:0, + limit:limit, + }, + + ...defaultRequestInfo, // Include default request metadata + }; + logger.info( + `Received a search request for census data with ID: ${planConfigId}` + ); + const planCensusResponse = await httpRequest( + config.host.censusServiceHost + config.paths.censusSearch, // Construct the request URL + searchBody // Pass the request body + ); + return planCensusResponse?.Census; // Return the response from the census search +}; + +/** + * Searches for plan configuration details based on configuration ID and tenant. + * @param planConfigId The unique identifier for the plan configuration. + * @param tenantId The tenant identifier for which the search is performed. + * @returns The response containing configuration details for the specified plan configuration. + */ +export const searchPlanConfig = async ( + planConfigId: string, + tenantId: string +) => { + const searchBody = { + PlanConfigurationSearchCriteria: { + tenantId: tenantId, + id: planConfigId, // Specify the plan configuration ID + }, + ...defaultRequestInfo, // Include default request metadata + }; + logger.info( + `Received a search request for plan configuration with ID: ${planConfigId}` + ); + const planConfigResponse = await httpRequest( + config.host.planServiceHost + config.paths.planConfigSearch, // Construct the request URL + searchBody // Pass the request body + ); + return planConfigResponse; // Return the response from the plan configuration search +}; diff --git a/health-services/project-factory/src/server/app.ts b/health-services/project-factory/src/server/app.ts index a51c4ab15bd..f662b76d104 100644 --- a/health-services/project-factory/src/server/app.ts +++ b/health-services/project-factory/src/server/app.ts @@ -1,10 +1,21 @@ -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'; -import { tracingMiddleware } from './tracing'; -import { createProxyMiddleware } from 'http-proxy-middleware'; +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"; +import { tracingMiddleware } from "./tracing"; +import { createProxyMiddleware } from "http-proxy-middleware"; +import * as v8 from "v8"; +import { logger } from "./utils/logger"; + +const printMemoryInMB = (memoryInBytes: number) => { + const memoryInMB = memoryInBytes / (1024 * 1024); // Convert bytes to MB + return `${memoryInMB.toFixed(2)} MB`; +}; class App { public app: express.Application; @@ -17,21 +28,43 @@ class App { this.initializeMiddlewares(); this.initializeControllers(controllers); this.app.use(invalidPathHandler); + + // Global error handling for uncaught exceptions + process.on("uncaughtException", (err) => { + console.error("Unhandled Exception:", err); + }); + + // Global error handling for unhandled promise rejections + process.on("unhandledRejection", (reason, promise) => { + console.error("Unhandled Rejection at:", promise, "reason:", reason); + }); } private initializeMiddlewares() { + this.app.use( + bodyParser.json({ limit: config.app.incomingRequestPayloadLimit }) + ); + this.app.use( + bodyParser.urlencoded({ + limit: config.app.incomingRequestPayloadLimit, + extended: true, + }) + ); this.app.use(bodyParser.json()); this.app.use(tracingMiddleware); this.app.use(requestMiddleware); this.app.use(errorLogger); this.app.use(errorResponder); - this.app.use('/tracing', createProxyMiddleware({ - target: 'http://localhost:16686', - changeOrigin: true, - pathRewrite: { - '^/tracing': '/', - }, - })); + this.app.use( + "/tracing", + createProxyMiddleware({ + target: "http://localhost:16686", + changeOrigin: true, + pathRewrite: { + "^/tracing": "/", + }, + }) + ); } private initializeControllers(controllers: any) { @@ -42,7 +75,34 @@ class App { public listen() { this.app.listen(this.port, () => { - console.log(`App listening on the port ${this.port}`); + logger.info(`App listening on the port ${this.port}`); + // Add periodic monitoring + setInterval(() => { + const stats = v8.getHeapStatistics(); + const usedHeapSize = stats.used_heap_size; + const heapLimit = stats.heap_size_limit; + + logger.debug( + JSON.stringify({ + "Heap Usage": { + used: printMemoryInMB(usedHeapSize), + limit: printMemoryInMB(heapLimit), + percentage: ((usedHeapSize / heapLimit) * 100).toFixed(2), + }, + }) + ); + + // Alert if memory usage is above 80% + if (usedHeapSize / heapLimit > 0.8) { + logger.warn("High memory usage detected"); + } + }, 5 * 60 * 1000); // Every 5 minutes + logger.info( + "Current App's Heap Configuration Total Available :", + printMemoryInMB(v8.getHeapStatistics()?.total_available_size), + " max limit set to : ", + printMemoryInMB(v8.getHeapStatistics()?.heap_size_limit) + ); }); } } diff --git a/health-services/project-factory/src/server/config/constants.ts b/health-services/project-factory/src/server/config/constants.ts index fffa89a7c87..73178392f23 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,12 @@ 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_NAME_NOT_MATCHING_PARENT_ERROR: "Campaign name different from parent Campaign", + CAMPAIGN_ALREADY_MAPPED: "Campaign is already mapped", + PARENT_CAMPAIGN_ERROR: "Parent Camapign error ", + INVALID_RESOURCE_DISTRIBUTION_STRATEGY: "Invalid resource distribution strategy", + RESOURCES_CONSOLIDATION_ERROR : "Error while consolidating resources in Campaign Update Flow " }, BOUNDARY: { BOUNDARY_DATA_NOT_FOUND: "No boundary data found in the system.", @@ -43,7 +49,9 @@ export const CONSTANTS: any = { 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" + BOUNDARY_CONFIRMATION_FAILED: "Error in boundary creation and persistence", + BOUNDARY_SHEET_UPLOADED_INVALID_ERROR: "Error in the boundary data uploaded", + BOUNDARY_SHEET_FIRST_COLUMN_INVALID_ERROR: "First Column Of Boundary Sheet uploaded should be unique as it is the root of hierarchy" }, PROJECT: { PROJECT_CREATION_FAILED: "Error occured in project creation", @@ -51,10 +59,17 @@ export const CONSTANTS: any = { 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", + PROJECT_STAFF_SEARCH_ERROR: "Error occured during project search , check projectId and staffId", + PROJECT_FACILITY_SEARCH_ERROR: "Error occured during project search , check projectId and facilityId", + PROJECT_FACILITY_DELETE_ERROR: "Error occured while deleting project facility mapping", + PROJECT_STAFF_DELETE_ERROR: "Error occured while deleting project staff mapping" }, MDMS: { INVALID_README_CONFIG: "Invalid readme config", MDMS_DATA_NOT_FOUND_ERROR: "Mdms Data not present" + }, + DATA:{ + DATA_CREATE_ERROR : "Error while creating resource data" } } } @@ -108,7 +123,40 @@ 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 => { // Retrieve the error message from the CONSTANTS object @@ -123,4 +171,4 @@ export const getErrorCodes = (module: string, key: string): Error => { notFound: true, message: message } -} +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/config/createAndSearch.ts b/health-services/project-factory/src/server/config/createAndSearch.ts index d89c45b7606..31f801d7e59 100644 --- a/health-services/project-factory/src/server/config/createAndSearch.ts +++ b/health-services/project-factory/src/server/config/createAndSearch.ts @@ -8,7 +8,7 @@ const createAndSearch: any = { } ], boundaryValidation: { - column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY" + column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY", }, sheetSchema: { "$schema": "http://json-schema.org/draft-07/schema#", @@ -132,14 +132,151 @@ const createAndSearch: any = { searchPath: "Facilities" } }, + "facilityMicroplan": { + requiresToSearchFromSheet: [ + { + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", + searchPath: "Facility.id" + } + ], + boundaryValidation: { + column: "HCM_ADMIN_CONSOLE_RESIDING_BOUNDARY_CODE_MICROPLAN" + }, + 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", } }, "user": { + requiresToSearchFromSheet: [ + { + sheetColumnName: "UserService Uuids", + searchPath: "user.mobileNumber" + }], boundaryValidation: { - column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY" + column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY", }, sheetSchema: { "$schema": "http://json-schema.org/draft-07/schema#", @@ -217,8 +354,10 @@ const createAndSearch: any = { } }, uniqueIdentifier: "user.userServiceUuid", - uniqueIdentifierColumn: "H", + uniqueIdentifierColumn: "I", uniqueIdentifierColumnName: "UserService Uuids", + activeColumn: "F", + activeColumnName: "HCM_ADMIN_CONSOLE_USER_USAGE", createBulkDetails: { limit: 50, createPath: "Employees", @@ -256,6 +395,14 @@ const createAndSearch: any = { boundaryValidation: { column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE" } + }, + "boundaryManagement": { + parseArrayConfig: { + sheetName: "HCM_ADMIN_CONSOLE_BOUNDARY_DATA", + }, + boundaryValidation: { + column: "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..862ac0a9059 100644 --- a/health-services/project-factory/src/server/config/index.ts +++ b/health-services/project-factory/src/server/config/index.ts @@ -12,29 +12,41 @@ if (!HOST) { const getDBSchemaName = (dbSchema = "") => { + // return "health"; return dbSchema ? (dbSchema == "egov" ? "public" : dbSchema) : "public"; } // Configuration object containing various environment variables const config = { + batchSize:100, + cacheTime: 300, + isProduction: process.env ? true : false, + token: "", // add default token if core services are not port forwarded + 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: "HierarchySchema", boundary: { boundaryCode: process.env.BOUNDARY_CODE_HEADER_NAME || "HCM_ADMIN_CONSOLE_BOUNDARY_CODE", + boundaryCodeMandatory: 'HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY', + boundaryCodeOld: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_OLD", 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", + facilityCodeColumn : "HCM_ADMIN_CONSOLE_FACILITY_CODE", + facilityType : "facility" }, user: { userTab: process.env.USER_TAB_NAME || "HCM_ADMIN_CONSOLE_USER_LIST", - 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 +56,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 +66,8 @@ 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_SAVE_PLAN_FACILITY_TOPIC: process.env.KAFKA_SAVE_PLAN_FACILITY_TOPIC || "project-factory-save-plan-facility", + KAFKA_TEST_TOPIC: "test-topic-project-factory", }, // Database configuration @@ -74,12 +88,17 @@ const config = { 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 + debugLogCharLimit: process.env.APP_MAX_DEBUG_CHAR ? Number(process.env.APP_MAX_DEBUG_CHAR) : 1000, + defaultTenantId: process.env.DEFAULT_TENANT_ID || "mz", + // incomingRequestPayloadLimit : process.env.REQUEST_PAYLOAD_LIMIT || "2mb" @ashish add this key and config helm chart values + incomingRequestPayloadLimit: "2mb" }, localisation: { defaultLocale: process.env.LOCALE || "en_MZ", - boundaryPrefix: "rainmaker-boundary", - localizationModule: process.env.LOCALIZATION_MODULE || "rainmaker-hcm-admin-schemas", + boundaryPrefix: "hcm-boundary", + localizationModule: process.env.LOCALIZATION_MODULE || "hcm-admin-schemas", + localizationWaitTimeInBoundaryCreation: parseInt(process.env.LOCALIZATION_WAIT_TIME_IN_BOUNDARY_CREATION || "30000"), + localizationChunkSizeForBoundaryCreation: parseInt(process.env.LOCALIZATION_CHUNK_SIZE_FOR_BOUNDARY_CREATION || "2000"), }, // targetColumnsForSpecificCampaigns: { // bedNetCampaignColumns: ["HCM_ADMIN_CONSOLE_TARGET"], @@ -104,12 +123,14 @@ const config = { hrmsHost: process.env.EGOV_HRMS_HOST || "https://unified-dev.digit.org/", localizationHost: process.env.EGOV_LOCALIZATION_HOST || "https://unified-dev.digit.org/", healthIndividualHost: process.env.EGOV_HEALTH_INDIVIDUAL_HOST || "https://unified-dev.digit.org/", - }, + planServiceHost: process.env.EGOV_PLAN_SERVICE_HOST || "https://unified-dev.digit.org/", + censusServiceHost: process.env.EGOV_CENSUS_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", + filestorefetch: "filestore/v1/files/url", + mdms_v2_search: process.env.EGOV_MDMS_V2_SEARCH_ENDPOINT || "mdms-v2/v2/_search", + mdms_v1_search: process.env.EGOV_MDMS_V1_SEARCH_ENDPOINT || "mdms-v2/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", @@ -131,28 +152,38 @@ const config = { localizationSearch: process.env.EGOV_LOCALIZATION_SEARCH || "localization/messages/v1/_search", localizationCreate: "localization/messages/v1/_upsert", projectTypeSearch: "project-factory/v1/project-type/search", + cacheBurst: process.env.CACHE_BURST || "localization/messages/cache-bust", boundaryRelationshipCreate: "boundary-service/boundary-relationships/_create", - mdmsV2SchemaSearch: "mdms-v2/schema/v1/_search", - mdms_v2_search: "mdms-v2/v2/_search", healthIndividualSearch: process.env.EGOV_HEALTH_INDIVIDUAL_SEARCH || "health-individual/v1/_search", - }, + projectFacilitySearch: process.env.EGOV_HEALTH_PROJECT_FACILITY_SEARCH || "health-project/facility/v1/_search", + projectStaffSearch: process.env.EGOV_HEALTH_PROJECT_STAFF_SEARCH || "health-project/staff/v1/_search", + projectFacilityDelete: process.env.EGOV_HEALTH_PROJECT_FACILITY_BULK_DELETE || "health-project/facility/v1/bulk/_delete", + projectStaffDelete: process.env.EGOV_HEALTH_PROJECT_STAFF_BULK_DELETE || "health-project/staff/v1/bulk/_delete", + planFacilitySearch: process.env.EGOV_PLAN_FACILITY_SEARCH || "plan-service/plan/facility/_search", + planConfigSearch: process.env.EGOV_PLAN_FACILITY_CONFIG_SEARCH || "plan-service/config/_search", + planSearch: process.env.EGOV_PLAN_SEARCH || "plan-service/plan/_search", + censusSearch: process.env.EGOV_CENSUS_SEARCH || "census-service/_search" }, // Values configuration values: { //module name unfrozeTillRow: process.env.UNFROZE_TILL_ROW || "10000", unfrozeTillColumn: process.env.UNFROZE_TILL_COLUMN || "50", moduleName: process.env.MODULE_NAME || "HCM-ADMIN-CONSOLE", - readMeTab: "HCM_README_SHEETNAME", + readMeTab: process.env.READ_ME_TAB || "HCM_README_SHEETNAME", 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" + idName: process.env.CMP_IDGEN_IDNAME || "campaign.number", + idNameForUserNameGeneration: "username.name", + formatForUserName: "USR-[SEQ_EG_USER_NAME]" }, matchFacilityData: false, retryCount: process.env.CREATE_RESOURCE_RETRY_COUNT || "3", notCreateUserIfAlreadyThere: process.env.NOT_CREATE_USER_IF_ALREADY_THERE || false, - maxHttpRetries: process.env.MAX_HTTP_RETRIES || "4" + maxHttpRetries: process.env.MAX_HTTP_RETRIES || "4", + skipResourceCheckValidationBeforeCreateForLocalTesting:false, // can be set to true for local development + autoRetryIfHttpError: process.env.AUTO_RETRY_IF_HTTP_ERROR || "socket hang up" // can be retry if there is any error for which default retry can be set } }; // Exporting getErrorCodes function and config object diff --git a/health-services/project-factory/src/server/config/models/SearchCriteria.ts b/health-services/project-factory/src/server/config/models/SearchCriteria.ts index 54d30a7d0e1..d5acc896484 100644 --- a/health-services/project-factory/src/server/config/models/SearchCriteria.ts +++ b/health-services/project-factory/src/server/config/models/SearchCriteria.ts @@ -17,6 +17,9 @@ export const searchCriteriaSchema = { }, "status": { "type": "string" + }, + "hierarchyType": { + "type": "string" } }, "required": ["tenantId"], diff --git a/health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts b/health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts index 873d2b5d034..61de751134b 100644 --- a/health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts +++ b/health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts @@ -19,7 +19,7 @@ export const campaignDetailsDraftSchema = { }, "action": { "type": "string", - "enum": ["create", "draft"], + "enum": ["create", "draft", "retry"], "maxLength": 64, "minLength": 1 }, @@ -92,6 +92,9 @@ export const campaignDetailsDraftSchema = { }, "additionalDetails": { "type": "object" + }, + "isActive":{ + "type":"boolean" } }, "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 index ed56e706d16..2f9b36bc136 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","boundaryManagement", "boundaryGeometryManagement"] }, "tenantId": { "type": "string", @@ -32,6 +32,9 @@ export const createRequestSchema = { }, "additionalDetails": { "type": "object" + }, + "isActive":{ + "type":"boolean" } }, "required": ["type", "tenantId", "fileStoreId", "action", "hierarchyType"], 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..759e3aa9d36 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", @@ -16,20 +16,32 @@ export const downloadRequestSchema = { "user", "boundary", "facilityWithBoundary", - "userWithBoundary" + "userWithBoundary", + "boundaryManagement", + "boundaryGeometryManagement" ] }, "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..1413905173a 100644 --- a/health-services/project-factory/src/server/config/models/generateRequestSchema.ts +++ b/health-services/project-factory/src/server/config/models/generateRequestSchema.ts @@ -12,11 +12,11 @@ export const generateRequestSchema = { "maxLength": 128, "minLength": 1, "enum": [ - "facility", - "user", "boundary", + "boundaryManagement", "facilityWithBoundary", - "userWithBoundary" + "userWithBoundary", + "boundaryGeometryManagement" ] }, "hierarchyType": { @@ -30,6 +30,9 @@ export const generateRequestSchema = { }, "campaignId": { "type": "string" + }, + "source": { + "type": "string", } }, "required": ["tenantId", "type", "hierarchyType", "campaignId"], diff --git a/health-services/project-factory/src/server/config/models/searchCampaignDetails.ts b/health-services/project-factory/src/server/config/models/searchCampaignDetails.ts index 155e8babbc4..8f4588ad79b 100644 --- a/health-services/project-factory/src/server/config/models/searchCampaignDetails.ts +++ b/health-services/project-factory/src/server/config/models/searchCampaignDetails.ts @@ -9,6 +9,9 @@ export const searchCampaignDetailsSchema = { "type": "string" } }, + "isActive":{ + "type":"boolean" + }, "tenantId": { "type": "string", "minLength": 1 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..1fd3e0646ea 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,7 +1,16 @@ import * as express from "express"; -import { createCampaignService, createProjectTypeCampaignService, searchProjectTypeCampaignService, updateProjectTypeCampaignService } from "../../service/campaignManageService"; +import { + createCampaignService, + createProjectTypeCampaignService, + fetchFromMicroplanService, + retryProjectTypeCampaignService, + searchProcessTracksService, + searchProjectTypeCampaignService, + updateProjectTypeCampaignService +} from "../../service/campaignManageService"; import { logger } from "../../utils/logger"; import { errorResponder, sendResponse } from "../../utils/genericUtils"; +import { validateSearchProjectCampaignRequest } from "../../validators/campaignValidators"; @@ -22,8 +31,13 @@ class campaignManageController { 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}/retry`, this.retryProjectTypeCampaign); this.router.post(`${this.path}/createCampaign`, this.createCampaign); + this.router.post(`${this.path}/getProcessTrack`, this.searchProcessTracks); + this.router.post(`${this.path}/fetch-from-microplan`, this.fetchFromMicroplan); } + + /** * Handles the creation of a project type campaign. * @param request The Express request object. @@ -77,7 +91,9 @@ class campaignManageController { ) => { try { logger.info("RECEIVED A PROJECT TYPE SEARCH REQUEST"); - const responseBody = await searchProjectTypeCampaignService(request); + // Validate the search request for project type campaigns + await validateSearchProjectCampaignRequest(request); + const responseBody = await searchProjectTypeCampaignService(request?.body?.CampaignDetails); // Send response with campaign details and total count return sendResponse(response, responseBody, request); } catch (e: any) { @@ -111,7 +127,58 @@ 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); + } + }; + + retryProjectTypeCampaign = async ( + request: express.Request, + response: express.Response + ) => { + try { + logger.info("RECEIVED A PROJECT TYPE RETRY REQUEST"); + const CampaignDetails = await retryProjectTypeCampaignService(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); + } + } + + fetchFromMicroplan = async ( + request: express.Request, + response: express.Response + ) => { + try { + logger.info("RECEIVED A FETCH FROM MICROPLAN REQUEST"); + const CampaignDetails = await fetchFromMicroplanService(request); + return sendResponse(response, { CampaignDetails }, 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); + } + } + }; + export default campaignManageController; 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 index 3591c1c016c..1c41ba84614 100644 --- a/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts +++ b/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts @@ -3,6 +3,7 @@ import { logger } from "../../utils/logger"; import { httpRequest } from "../../utils/request"; import config from "../../config/index"; import { convertLocalisationResponseToMap } from "../../utils/localisationUtils"; +import { defaultRequestInfo } from "../../api/coreApis"; let cachedResponse = {}; @@ -15,7 +16,7 @@ class Localisation { // Hold the single instance of the class private static instance: Localisation; constructor() { - this.localizationHost = config.host.localizationHost + this.localizationHost = config.host.localizationHost; } // Public method to provide access to the single instance public static getInstance(): Localisation { @@ -36,12 +37,13 @@ class Localisation { public getLocalisedData: any = async ( module: string, locale: string, - tenantId: string + tenantId: string, + overrideCache: boolean ) => { logger.info( `Checks Localisation message is available in cache for module ${module}, locale ${locale}, tenantId ${tenantId}` ); - if (!this?.cachedResponse?.[`${module}-${locale}`]) { + if (!this?.cachedResponse?.[`${module}-${locale}`] || overrideCache) { logger.info(`Not found in cache`); await this.fetchLocalisationMessage(module, locale, tenantId); } @@ -81,6 +83,34 @@ class Localisation { ); cachedResponse = { ...this.cachedResponse }; }; + + // Calls the cache burst API of localization + public cacheBurst = async ( + ) => { + logger.info(`Calling localization cache burst api`); + const RequestInfo = defaultRequestInfo; + const requestBody = { + RequestInfo + } + await httpRequest( + this.localizationHost + config.paths.cacheBurst, + requestBody) + }; + + + private checkCacheAndDeleteIfExists = (module: string, locale: "string") => { + logger.info( + `Received to checkCacheAndDeleteIfExists for module ${module}, locale ${locale}` + ); + if (this.cachedResponse?.[`${module}-${locale}`]) { + logger.info(`cache found to for module ${module}, locale ${locale}`); + if (delete this.cachedResponse?.[`${module}-${locale}`]) { + logger.info( + `cache deleted for module ${module}, locale ${locale}, since new data has been created` + ); + } + } + }; /** * Create localisation entries by sending a POST request to the localization host. @@ -98,19 +128,26 @@ class Localisation { // 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; + const url = this.localizationHost + config.paths.localizationCreate; // Log the start of the localisation messages creation process - logger.info("Creating the localisation messages"); + logger.info(`Creating the localisation messages of count ${messages?.length}`); // Send HTTP POST request to create localisation messages await httpRequest(url, requestBody); + + messages && + messages?.length > 0 && + this.checkCacheAndDeleteIfExists( + messages?.[0]?.module, + messages?.[0]?.locale + ); // 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)); + throw new Error(e); } }; } 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..cafa0ac6f66 100644 --- a/health-services/project-factory/src/server/kafka/Producer.ts +++ b/health-services/project-factory/src/server/kafka/Producer.ts @@ -1,25 +1,112 @@ -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 +import { Producer, KafkaClient } from 'kafka-node'; +import { getFormattedStringForDebug, logger } from "../utils/logger"; +import { shutdownGracefully, throwError } from '../utils/genericUtils'; +import config from '../config'; + +let kafkaClient: KafkaClient; +let producer: Producer; + +const createKafkaClientAndProducer = () => { + kafkaClient = new KafkaClient({ + kafkaHost: config?.host?.KAFKA_BROKER_HOST, + connectRetryOptions: { retries: 1 }, + }); + + // 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(); + }); + + producer = new Producer(kafkaClient, { partitionerType: 2 }); + + 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 sendWithReconnect = (payloads: any[]): Promise => { + return new Promise((resolve, reject) => { + // Send the message initially + producer.send(payloads, async (err: any) => { + if (err) { + logger.error('Error sending message:', err); + logger.debug(`Was trying to send: ${getFormattedStringForDebug(payloads)}`); + + // Attempt to reconnect and retry + logger.error('Reconnecting producer and retrying...'); + producer.close(() => { + createKafkaClientAndProducer(); + setTimeout(() => { + // Retry sending after reconnection + producer.send(payloads, (err: any) => { + if (err) { + logger.error('Failed to send message after reconnection:', err); + return reject(err); // Final failure, reject promise + } else { + logger.info('Message sent successfully after reconnection'); + resolve(); + } + }); + }, 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 sendWithReconnect(payloads); + } 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/models/Boundary.d.ts b/health-services/project-factory/src/server/models/Boundary.d.ts new file mode 100644 index 00000000000..576ef939992 --- /dev/null +++ b/health-services/project-factory/src/server/models/Boundary.d.ts @@ -0,0 +1,115 @@ +import { AuditDetails } from "./MDMS"; + +/** + * Represents the response structure for a boundary entity search. + */ +export interface BoundaryEntityResponse { + /** Array of boundary entities returned in the response */ + Boundary: BoundaryEntity[]; +} + +/** + * Represents a boundary entity within the MDMS system. + */ +interface BoundaryEntity { + /** Unique identifier for the boundary entity */ + id: string; + /** Tenant ID associated with the boundary entity */ + tenantId: string; + /** Unique code representing the boundary entity */ + code: string; + /** Geographical data for the boundary entity */ + geometry: any; + /** Audit information such as created/modified timestamps and users */ + auditDetails: AuditDetails; + /** Additional details related to the boundary entity */ + additionalDetails: any; +} + +/** + * Represents the response structure for a boundary hierarchy definition search. + */ +export interface BoundaryHierarchyDefinitionResponse { + /** Array of boundary hierarchy definitions in the response */ + BoundaryHierarchy: BoundaryHierarchy[]; +} + +/** + * Defines a boundary hierarchy within the MDMS system. + */ +interface BoundaryHierarchy { + /** Unique identifier for the hierarchy */ + id: string; + /** Tenant ID associated with the hierarchy */ + tenantId: string; + /** Type of hierarchy (e.g., administrative, geographic) */ + hierarchyType: string; + /** Elements representing each level within the hierarchy */ + boundaryHierarchy: BoundaryHierarchyElement[]; + /** Audit information such as created/modified timestamps and users */ + auditDetails: AuditDetails; +} + +/** + * Represents an element in the boundary hierarchy. + */ +interface BoundaryHierarchyElement { + /** Type of boundary at this level of the hierarchy */ + boundaryType: string; + /** Type of the parent boundary, if applicable */ + parentBoundaryType: null | string; + /** Indicates if the boundary is active */ + active: boolean; +} + +/** + * Represents the response structure for a boundary hierarchy relationship search. + */ +export interface BoundaryHierarchyRelationshipResponse { + /** Array of tenant boundaries returned in the response */ + TenantBoundary: TenantBoundary[]; +} + +/** + * Represents a tenant boundary structure within the MDMS system. + */ +interface TenantBoundary { + /** Tenant ID associated with this boundary */ + tenantId: string; + /** Type of hierarchy within which the boundary is categorized */ + hierarchyType: string; + /** Array of boundaries within this tenant's hierarchy */ + boundary: Boundary[]; +} + +/** + * Represents an individual boundary within a hierarchy, which may contain nested child boundaries. + */ +interface Boundary { + /** Unique identifier for the boundary */ + id: string; + /** Code representing the boundary */ + code: string; + /** Type of boundary (e.g., city, region) */ + boundaryType: string; + /** Array of child boundaries, allowing nested hierarchies */ + children: Boundary[]; +} + +/** + * Represents the search criteria for querying boundary hierarchy definitions. + */ +export interface BoundaryHierarchyDefinitionSearchCriteria { + /** Contains criteria for boundary type hierarchy search */ + BoundaryTypeHierarchySearchCriteria: BoundaryTypeHierarchySearchCriteria; +} + +/** + * Defines the criteria for searching a specific boundary type hierarchy. + */ +interface BoundaryTypeHierarchySearchCriteria { + /** Tenant ID for filtering the search results */ + tenantId: string; + /** Type of hierarchy being queried (e.g., administrative levels) */ + hierarchyType: string; +} diff --git a/health-services/project-factory/src/server/models/MDMS.d.ts b/health-services/project-factory/src/server/models/MDMS.d.ts new file mode 100644 index 00000000000..0a163e14f1c --- /dev/null +++ b/health-services/project-factory/src/server/models/MDMS.d.ts @@ -0,0 +1,144 @@ +/** + * Criteria for MDMS v1 request + */ +interface MDMSv1Criteria { + tenantId: string; // Unique identifier for the tenant + moduleDetails: ModuleDetail[]; // Array of module details to fetch +} + +/** + * Represents details of a specific module in MDMS v1 + */ +interface ModuleDetail { + moduleName: string; // Name of the module + masterDetails: MasterDetail[]; // Array of master data details for this module +} + +/** + * Details of a specific master entity in a module + */ +interface MasterDetail { + name: string; // Name of the master entity + filter?: string; // Optional filter criteria for fetching specific master data +} + +/** + * Criteria for MDMS v2 request + */ +interface MDMSv2Criteria { + tenantId: string; // Unique identifier for the tenant + schemaCode: string; // Code representing the schema to query + ids?: string[]; // Optional array of specific IDs to fetch + uniqueIdentifiers?: string[]; // Optional array of unique identifiers for the data +} + +/** + * Response structure for MDMS v1 response + */ +export interface MDMSv1Response { + MdmsRes: any; // Response payload, structure may vary +} + +/** + * Response structure for MDMS v2 response + */ +export interface MDMSv2Response { + mdms: MDMS[]; // Array of MDMS records +} + +/** + * Represents a single MDMS record in v2 response + */ +interface MDMS { + id: string; // Unique identifier for the MDMS record + tenantId: string; // Tenant identifier for the record + schemaCode: string; // Schema code associated with this record + uniqueIdentifier: string; // Unique identifier within this schema + data: any; // Data payload for the record + isActive: boolean; // Indicates if the record is active + auditDetails: AuditDetails; // Audit details for tracking changes +} + +/** + * Audit details containing metadata about record creation and modification + */ +interface AuditDetails { + createdBy: string; // ID of the user who created the record + lastModifiedBy: string; // ID of the user who last modified the record + createdTime: number; // Timestamp when the record was created + lastModifiedTime: number; // Timestamp when the record was last modified +} + +/** + * Response structure for MDMS schema definitions + */ +export interface MDMSSchemaResponse { + SchemaDefinitions: SchemaDefinition[]; // Array of schema definitions +} + +/** + * Represents a single schema definition in the MDMS response + */ +interface SchemaDefinition { + id: string; // Unique identifier for the schema definition + tenantId: string; // Tenant identifier associated with this schema + code: string; // Code identifying the schema + description: null | string; // Description of the schema, if available + definition: Definition; // Schema structure definition + isActive: boolean; // Indicates if the schema is active + auditDetails: AuditDetails; // Audit metadata for the schema definition +} + +/** + * Detailed structure of a schema definition + */ +interface Definition { + type: string; // Type of schema (e.g., object, array) + title?: string; // Optional title of the schema + $schema: string; // URI of the schema + required: string[]; // Array of required fields + "x-unique": string[]; // Array of unique constraints + properties?: any; // Properties within the schema + "x-ref-schema"?: XRefSchema[]; // Array of cross-references to other schemas + description?: string; // Optional description of the schema + additionalProperties?: boolean; // Indicates if additional properties are allowed + unique?: string[]; // Array of fields that must be unique +} + +/** + * Cross-reference schema for related fields + */ +interface XRefSchema { + fieldPath: string; // Path to the field within the schema + schemaCode: string; // Code of the schema that is referenced +} + +/** + * Criteria for requesting MDMS schema definitions + */ +export interface MDMSSchemaRequestCriteria { + SchemaDefCriteria: SchemaDefCriteria; // Criteria details for schema definition request +} + +/** + * Detailed criteria structure for schema definition requests + */ +interface SchemaDefCriteria { + tenantId: string; // Tenant identifier for the schema definition + limit: number; // Limit on the number of schema definitions to fetch + codes?: string[]; // Optional array of schema codes to retrieve +} + +/** + * Criteria for requesting MDMS schema definitions + */ +export interface MDMSv1RequestCriteria { + MdmsCriteria: MDMSv1Criteria; // Criteria details for schema definition request +} + +/** + * Criteria for requesting MDMS schema definitions + */ +export interface MDMSv2RequestCriteria { + MdmsCriteria: MDMSv2Criteria; // Criteria details for schema definition request +} diff --git a/health-services/project-factory/src/server/models/index.ts b/health-services/project-factory/src/server/models/index.ts new file mode 100644 index 00000000000..bd0e5462792 --- /dev/null +++ b/health-services/project-factory/src/server/models/index.ts @@ -0,0 +1,8 @@ +import * as MDMSModels from './MDMS'; +import * as BoundaryModels from './Boundary'; + + +export { + MDMSModels, + BoundaryModels +}; diff --git a/health-services/project-factory/src/server/service/campaignManageService.ts b/health-services/project-factory/src/server/service/campaignManageService.ts index 3d3652bb441..bd9ce407221 100644 --- a/health-services/project-factory/src/server/service/campaignManageService.ts +++ b/health-services/project-factory/src/server/service/campaignManageService.ts @@ -1,15 +1,17 @@ import express from "express"; -import { processBasedOnAction, searchProjectCampaignResourcData } from "../utils/campaignUtils"; +import { processBasedOnAction, processFetchMicroPlan, searchProjectCampaignResourcData, updateCampaignAfterSearch } from "../utils/campaignUtils"; import { logger } from "../utils/logger"; -import { validateProjectCampaignRequest, validateSearchProjectCampaignRequest } from "../validators/campaignValidators"; +import { validateMicroplanRequest, validateProjectCampaignRequest, validateSearchProcessTracksRequest } 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 + logger.info("VALIDATING:: for project type"); await validateProjectCampaignRequest(request, "create"); - logger.info("VALIDATED THE PROJECT TYPE CREATE REQUEST"); + logger.info("VALIDATED:: THE PROJECT TYPE CREATE REQUEST"); // Process the action based on the request type await processBasedOnAction(request, "create"); @@ -26,16 +28,14 @@ async function updateProjectTypeCampaignService(request: express.Request) { return request?.body?.CampaignDetails; } -async function searchProjectTypeCampaignService( - request: express.Request, +async function searchProjectTypeCampaignService(campaignDetails: any ) { - // Validate the search request for project type campaigns - await validateSearchProjectCampaignRequest(request); + // 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 } + const { responseData, totalCount } = await searchProjectCampaignResourcData(campaignDetails); + const responseBody: any = { CampaignDetails: responseData, totalCount: totalCount } return responseBody; }; @@ -53,10 +53,47 @@ 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 +}; + +async function retryProjectTypeCampaignService(request: express.Request) { + logger.info("RETRYING THE PROJECT TYPE CAMPAIGN"); + await validateProjectCampaignRequest(request, "retry"); + logger.info("VALIDATED THE PROJECT TYPE RETRY REQUEST"); + request.body.CampaignDetails.action = "draft"; + await processBasedOnAction(request, "update"); + return request?.body?.CampaignDetails; +} + +async function fetchFromMicroplanService(request: express.Request) { + logger.info("FETCHING DATA FROM MICROPLAN"); + await validateMicroplanRequest(request); + logger.info("UPDATE CAMPAIGN OBJECT") + await updateCampaignAfterSearch(request, "MICROPLAN_FETCHING") + logger.info("Validated request successfully"); + processFetchMicroPlan(request); + return request.body.CampaignDetails; +} + export { createProjectTypeCampaignService, updateProjectTypeCampaignService, searchProjectTypeCampaignService, - createCampaignService -} \ No newline at end of file + createCampaignService, + searchProcessTracksService, + retryProjectTypeCampaignService, + fetchFromMicroplanService +} diff --git a/health-services/project-factory/src/server/service/dataManageService.ts b/health-services/project-factory/src/server/service/dataManageService.ts index ed224dc824f..bf1f17b8355 100644 --- a/health-services/project-factory/src/server/service/dataManageService.ts +++ b/health-services/project-factory/src/server/service/dataManageService.ts @@ -1,14 +1,19 @@ import express from "express"; 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 { getLocalizedName, getResourceDetails, processDataSearchRequest } from "../utils/campaignUtils"; +import { addDataToSheet, enrichResourceDetails, getLocalizedMessagesHandler, searchGeneratedResources, processGenerate, replicateRequest } from "../utils/genericUtils"; +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' +import { callGenerate } from "../utils/generateUtils"; +import { generatedResourceStatuses } from "../config/constants"; + const generateDataService = async (request: express.Request) => { @@ -28,34 +33,89 @@ const downloadDataService = async (request: express.Request) => { const type = request.query.type; // Get response data from the database const responseData = await searchGeneratedResources(request); + const resourceDetails = await getResourceDetails(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 ") + if ( + !responseData || + (responseData.length === 0 && !request?.query?.id) || + responseData?.[0]?.status === generatedResourceStatuses.failed + ) { + logger.error(`No data of type '${type}' with status 'Completed' or the provided ID is present in the database.`) // Throw error if data is not found - throwError("CAMPAIGN", 500, "GENERATION_REQUIRE"); + const newRequestBody = { + RequestInfo: request?.body?.RequestInfo + }; + const params = { + type: request?.query?.type, + tenantId: request?.query?.tenantId, + forceUpdate: 'true', + hierarchyType: request?.query?.hierarchyType, + campaignId: request?.query?.campaignId, + }; + const newRequestToGenerate = replicateRequest(request, newRequestBody, params); + // Added auto generate since no previous generate request found + logger.info(`Triggering auto generate since no resources got generated for the given Campaign Id ${request?.query?.campaignId} & type ${request?.query?.type} `) + callGenerate(newRequestToGenerate, request?.query?.type); + + // throwError("CAMPAIGN", 500, "GENERATION_REQUIRE"); + } + + // Send response with resource details + if (resourceDetails != null && responseData != null && responseData.length > 0) { + responseData[0].additionalDetails = { + ...(responseData[0].additionalDetails || {}), + ...(resourceDetails?.additionalDetails || {}) + }; } + + return responseData; } 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 localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler(request, request?.query?.tenantId, getLocalisationModuleName(hierarchyType), true); const localizationMapModule = await getLocalizedMessagesHandler(request, request?.query?.tenantId); - const localizationMap = { ...localizationMapHierarchy, ...localizationMapModule }; + 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); + addDataToSheet(request, boundarySheet, boundarySheetData, '93C47D', 40, true); + 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); @@ -65,7 +125,10 @@ const getBoundaryDataService = async ( const createDataService = async (request: any) => { - const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId); + const hierarchyType = request?.body?.ResourceDetails?.hierarchyType; + const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId, getLocalisationModuleName(hierarchyType), true); + const localizationMapModule = await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId); + const localizationMap = { ...(localizationMapHierarchy || {}), ...localizationMapModule }; // Validate the create request logger.info("Validating data create request") await validateCreateRequest(request, localizationMap); @@ -95,4 +158,4 @@ export { getBoundaryDataService, createDataService, searchDataService -} \ No newline at end of file +} diff --git a/health-services/project-factory/src/server/utils/boundariesConsolidationUtils.ts b/health-services/project-factory/src/server/utils/boundariesConsolidationUtils.ts new file mode 100644 index 00000000000..568657d168d --- /dev/null +++ b/health-services/project-factory/src/server/utils/boundariesConsolidationUtils.ts @@ -0,0 +1,44 @@ +import config from "../config/index"; +import { httpRequest } from "./request"; +import { processBoundary } from "./campaignUtils"; + +async function consolidateBoundaries(messageObject: any, hierarchyType: any, tenantId: any, code: any, boundaries: any) { + const params = { + tenantId: tenantId, + codes: code, + hierarchyType: hierarchyType, + includeChildren: true, + }; + const header = { + cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId + }${params.codes || ""}${params?.includeChildren || ""}`, + }; + const boundaryResponse = await httpRequest( + config.host.boundaryHost + config.paths.boundaryRelationship, + messageObject?.RequestInfo, + params, + undefined, + undefined, + header + ); + if (boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]) { + const boundaryChildren = boundaries.reduce((acc: any, boundary: any) => { + acc[boundary.code] = boundary?.includeAllChildren; + return acc; + }, {}); + const 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 + ); + return boundaries; + } +} +export { consolidateBoundaries, } \ No newline at end of file diff --git a/health-services/project-factory/src/server/utils/boundaryUtils.ts b/health-services/project-factory/src/server/utils/boundaryUtils.ts index 40aa4f437ed..9b6e0396d19 100644 --- a/health-services/project-factory/src/server/utils/boundaryUtils.ts +++ b/health-services/project-factory/src/server/utils/boundaryUtils.ts @@ -1,4 +1,6 @@ import config from "../config/index"; +import { logger } from "./logger"; +import { httpRequest } from "./request"; @@ -13,3 +15,54 @@ export const getBoundaryTabName = () => { return config?.boundary?.boundaryTab; }; + +export async function getLatLongMapForBoundaryCodes(request:any, boundaryCodeList: any[]) { + const chunkSize = 20; + const boundaryCodeChunks = []; + let boundaryCodeLatLongMap: { [key: string]: number[] } = {}; // Map to hold lat/long data for boundary codes + + // Split the boundaryCodeList into chunks of 20 + for (let i = 0; i < boundaryCodeList.length; i += chunkSize) { + boundaryCodeChunks.push(boundaryCodeList.slice(i, i + chunkSize)); + } + + // Process each chunk + for (const chunk of boundaryCodeChunks) { + const boundaryCodeString = chunk.join(", "); + + // Only proceed if there are valid boundary codes + if (boundaryCodeList.length > 0 && boundaryCodeString) { + logger.info(`Creating boundary entities for codes: ${boundaryCodeString}`); + + try { + // Make the API request to fetch boundary entities + const boundaryEntityResponse = await httpRequest( + config.host.boundaryHost + config.paths.boundaryEntity, + request.body, // Passing the request body + { tenantId: request?.query?.tenantId, codes: boundaryCodeString } // Query params + ); + + // Process the boundary entities and extract lat/long for 'Point' geometries + if (boundaryEntityResponse?.Boundary) { + for (const boundary of boundaryEntityResponse.Boundary) { + if (boundary?.geometry && boundary.geometry.type === "Point") { + boundaryCodeLatLongMap[boundary.code] = boundary.geometry.coordinates; + } + } + } + + } catch (error: any) { + // Log error but do not stop the process for other chunks + console.log(error); + logger.error(`Failed to fetch boundary entities for codes: ${boundaryCodeString}, Error: ${error.message}`); + } + + } else { + // Log when the chunk is empty or invalid + logger.debug(`Skipping empty or invalid chunk: ${boundaryCodeString}`); + } + } + boundaryCodeLatLongMap['ADMIN_MO'] = [200,100]; + // Return or process the map further if needed + return boundaryCodeLatLongMap; +} diff --git a/health-services/project-factory/src/server/utils/campaignMappingUtils.ts b/health-services/project-factory/src/server/utils/campaignMappingUtils.ts index ac34761d2f8..a6f1b821c00 100644 --- a/health-services/project-factory/src/server/utils/campaignMappingUtils.ts +++ b/health-services/project-factory/src/server/utils/campaignMappingUtils.ts @@ -1,12 +1,19 @@ import createAndSearch from "../config/createAndSearch"; import config from "../config"; -import { getDataFromSheet, throwError } from "./genericUtils"; +import { getDataFromSheet, getLocalizedMessagesHandlerViaRequestInfo, replicateRequest, 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 { createCampaignService, searchProjectTypeCampaignService } from "../service/campaignManageService"; +import { persistTrack } from "./processTrackUtils"; +import { processTrackTypes, processTrackStatuses } from "../config/constants"; +import { createProjectFacilityHelper, createProjectResourceHelper, createProjectStaffHelper } from "../api/genericApis"; +import { buildSearchCriteria, delinkAndLinkResourcesWithProjectCorrespondingToGivenBoundary, processResources } from "./onGoingCampaignUpdateUtils"; +import { searchDataService } from "../service/dataManageService"; +import { getHierarchy } from "../api/campaignApis"; +import { consolidateBoundaries } from "./boundariesConsolidationUtils"; async function createBoundaryWithProjectMapping(projects: any, boundaryWithProject: any) { @@ -20,54 +27,249 @@ async function createBoundaryWithProjectMapping(projects: any, boundaryWithProje } } -function getPvarIds(messageObject: any) { +export function getPvarIds(messageObject: any) { + //update to set now + logger.info("campaign product resource mapping started"); 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; + const products = deliveryRule?.resources; if (products) { for (const product of products) { - uniquePvarIds.add(product?.value); // Add pvar ID to the Set + uniquePvarIds.add(product?.productVariantId); // Add pvar ID to the Set } } } } + logger.info(`campaign product resource found items : ${JSON.stringify(uniquePvarIds)}`); 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 + ? boundaryCode.includes(',') + ? boundaryCode.split(',').map((bc: string) => bc.trim()).filter(Boolean) + : [boundaryCode.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}`) + }); + } +} + + +function splitBoundaryCodes(boundaryCode: string) { + return boundaryCode.includes(',') + ? boundaryCode.split(',').map((code: string) => code.trim()).filter(Boolean) + : [boundaryCode.trim()].filter(Boolean); +} + + +async function fetchActiveIdentifiersFromParentCampaign( + resource: any, + resourcesFromParentCampaign: any[], + messageObject: any, + sheetName: any, + localizationMap: any, + activeColumn: string, + uniqueCodeColumn: string +): Promise { + let activeUniqueIdentifiersFromParent: any[] = []; + + if (messageObject?.parentCampaign) { + const matchingParentResource = resourcesFromParentCampaign.find( + (parentResource: any) => parentResource.type === resource.type + ); + + if (matchingParentResource) { + const parentCreateResourceId = matchingParentResource.createResourceId || ''; + const searchCriteria = buildSearchCriteria(messageObject, [parentCreateResourceId], matchingParentResource?.type); + const responseFromDataSearch = await searchDataService(replicateRequest(messageObject, searchCriteria)); + + const parentProcessedFileStoreId = responseFromDataSearch?.[0]?.processedFilestoreId; + + const parentResourceData: any = await getDataFromSheet( + messageObject, + parentProcessedFileStoreId, + messageObject?.Campaign?.tenantId, + undefined, + sheetName[matchingParentResource?.type], + localizationMap + ); + + activeUniqueIdentifiersFromParent = parentResourceData + .filter((row: any) => row[activeColumn] === "Active") + .map((row: any) => row[uniqueCodeColumn]); + } + } + + return activeUniqueIdentifiersFromParent; +} + + 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); + const delinkOperations: any = []; + const linkOperations: any = []; + const resourcesFromParentCampaign = messageObject?.parentCampaign?.resources || []; for (const resource of resources) { + const uniqueCodeColumn = getLocalizedName(createAndSearch?.[resource?.type]?.uniqueIdentifierColumnName, localizationMap) + let activeColumn: any; + if (createAndSearch?.[resource?.type]?.activeColumn && createAndSearch?.[resource?.type]?.activeColumnName) { + activeColumn = getLocalizedName(createAndSearch?.[resource?.type]?.activeColumnName, localizationMap); + } const processedFilestoreId = resource?.processedFilestoreId; + const activeUniqueIdentifiersFromParent = await fetchActiveIdentifiersFromParentCampaign( + resource, + resourcesFromParentCampaign, + messageObject, + sheetName, + localizationMap, + activeColumn, + uniqueCodeColumn + ); 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]; if (code) { // Extract boundary codes const boundaryCode = data[getLocalizedName(createAndSearch?.[resource?.type]?.boundaryValidation?.column, localizationMap)]; - var active: any = "Active"; + let active: any = "Active"; if (createAndSearch?.[resource?.type]?.activeColumn && createAndSearch?.[resource?.type]?.activeColumnName) { - var activeColumn = getLocalizedName(createAndSearch?.[resource?.type]?.activeColumnName, localizationMap); 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] = []; + if (boundaryCode && active === "Active") { + if (!messageObject?.parentCampaign) { + mapBoundaryCodes(resource, code, boundaryCode, boundaryCodes, allBoundaries); + } + else { + const existingBoundaryColumn = splitBoundaryCodes( + data[getLocalizedName("HCM_ADMIN_CONSOLE_BOUNDARY_CODE_OLD", localizationMap)] || "" + ); + + const newBoundaryColumn = splitBoundaryCodes(boundaryCode); + + existingBoundaryColumn.forEach((boundary: any) => { + if (!newBoundaryColumn.includes(boundary)) { + delinkOperations.push({ + resource, messageObject, boundary, code, isDelink: true + }); + } + }); + + // Collect link operations for new boundaries + newBoundaryColumn.forEach((boundary: any) => { + linkOperations.push({ + resource, messageObject, boundary, code, isDelink: false + }); + }); + } + } + else { + if (messageObject?.parentCampaign) { + if (boundaryCode && activeUniqueIdentifiersFromParent.includes(code) && active !== "Active") { + const boundariesToBeDelinked = splitBoundaryCodes(data[getLocalizedName("HCM_ADMIN_CONSOLE_BOUNDARY_CODE_OLD", localizationMap)] || ""); + boundariesToBeDelinked.forEach((boundary: any) => { + delinkOperations.push({ + resource, messageObject, boundary, code, isDelink: true + }); + }); + } - boundaryCodes[resource?.type][trimmedBC].push(code); - logger.info(`Boundary code ${trimmedBC} mapped to resource ${resource?.type} with code ${code}`) - }); + } } } else { @@ -76,6 +278,41 @@ async function enrichBoundaryCodes(resources: any[], messageObject: any, boundar } } } + + // Process delink operations sequentially + for (const delinkData of delinkOperations) { + try { + const isMappingAlreadyPresent = await delinkAndLinkResourcesWithProjectCorrespondingToGivenBoundary( + delinkData.resource, + delinkData.messageObject, + delinkData.boundary, + delinkData.code, + delinkData.isDelink + ); + logger.info(`Delinking ${delinkData.boundary} from ${delinkData.code} resource`); + logger.info("Delink operation complete, mapping present:", isMappingAlreadyPresent); + } catch (err: any) { + logger.error(`Error during delink operation for ${delinkData.boundary}: ${err.message}`); + } + } + + // Process link operations sequentially + for (const linkData of linkOperations) { + try { + const isMappingAlreadyPresent = await delinkAndLinkResourcesWithProjectCorrespondingToGivenBoundary( + linkData.resource, + linkData.messageObject, + linkData.boundary, + linkData.code, + linkData.isDelink + ); + if (!isMappingAlreadyPresent) { + mapBoundaryCodes(linkData.resource, linkData.code, linkData.boundary, boundaryCodes, allBoundaries); + } + } catch (err: any) { + logger.error(`Error during link operation for ${linkData.boundary}: ${err.message}`); + } + } } @@ -101,6 +338,21 @@ async function enrichBoundaryWithProject(messageObject: any, boundaryWithProject logger.debug(`boundaryWise Project mapping : ${getFormattedStringForDebug(boundaryWithProject)}`); logger.info("boundaryCodes mapping : " + JSON.stringify(boundaryCodes)); } +function filterBoundariesByHierarchy(hierarchy: any, boundaries: any) { + // Iterate through the hierarchy in order + for (const level of hierarchy) { + // Find boundaries matching the current level type + const matchingBoundaries = boundaries.filter((boundary: any) => boundary.type === level); + + if (matchingBoundaries.length > 0) { + // If matches are found, return them + return matchingBoundaries; + } + } + + // If no matches are found, return an empty array + return []; +} async function getProjectMappingBody(messageObject: any, boundaryWithProject: any, boundaryCodes: any) { const Campaign: any = { @@ -108,16 +360,60 @@ async function getProjectMappingBody(messageObject: any, boundaryWithProject: an tenantId: messageObject?.Campaign?.tenantId, CampaignDetails: [] } + const newlyAddedBoundaryCodes = new Set(); // A set to store unique boundary codes + if (messageObject?.CampaignDetails?.parentId) { + const CampaignDetails = { + "ids": [messageObject?.CampaignDetails?.id], + "tenantId": messageObject?.CampaignDetails?.tenantId + } + const campaignSearchResponse = await searchProjectTypeCampaignService(CampaignDetails); + const boundaries = campaignSearchResponse?.CampaignDetails?.[0]?.boundaries; + const hierarchy = await getHierarchy(messageObject, messageObject?.CampaignDetails?.tenantId, messageObject?.CampaignDetails?.hierarchyType); + const boundariesWhichAreRootInThisFlow = filterBoundariesByHierarchy(hierarchy, boundaries); + for (const boundary of boundariesWhichAreRootInThisFlow) { + const boundaryCodesFetchedFromGivenRoot = await consolidateBoundaries( + messageObject, + messageObject?.CampaignDetails?.hierarchyType, + messageObject?.CampaignDetails?.tenantId, + boundary?.code, + boundaries + ); + // Add each boundary code to the set if it exists + if (boundaryCodesFetchedFromGivenRoot && + Array.isArray(boundaryCodesFetchedFromGivenRoot) && + boundaryCodesFetchedFromGivenRoot.length > 0) { + boundaryCodesFetchedFromGivenRoot + .filter((boundary: any) => boundary?.code) // Filter boundaries with valid codes + .forEach((boundary: any) => newlyAddedBoundaryCodes.add(boundary.code)); + } + } + } + + for (const key of Object.keys(boundaryWithProject)) { if (boundaryWithProject[key]) { const resources: any[] = []; - const pvarIds = getPvarIds(messageObject); - if (pvarIds && Array.isArray(pvarIds) && pvarIds.length > 0) { - resources.push({ - type: "resource", - resourceIds: pvarIds - }) + if (messageObject?.CampaignDetails?.parentId && newlyAddedBoundaryCodes.has(key)) { + logger.info("project resource mapping for newly created projects in update flow") + const pvarIds = getPvarIds(messageObject); + if (pvarIds && Array.isArray(pvarIds) && pvarIds.length > 0) { + resources.push({ + type: "resource", + resourceIds: pvarIds + }) + } + } + + if (!messageObject?.CampaignDetails?.parentId) { + const pvarIds = getPvarIds(messageObject); + if (pvarIds && Array.isArray(pvarIds) && pvarIds.length > 0) { + resources.push({ + type: "resource", + resourceIds: pvarIds + }) + } } + for (const type of Object.keys(boundaryCodes)) { if (boundaryCodes[type][key] && Array.isArray(boundaryCodes[type][key]) && boundaryCodes[type][key].length > 0) { resources.push({ @@ -129,39 +425,45 @@ async function getProjectMappingBody(messageObject: any, boundaryWithProject: an Campaign.CampaignDetails.push({ projectId: boundaryWithProject[key], resources: resources - }) + }); } } return { RequestInfo: messageObject?.RequestInfo, - Campaign: Campaign + Campaign: Campaign, + CampaignDetails: messageObject?.CampaignDetails, + parentCampaign: messageObject?.parentCampaign } } 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 +504,200 @@ 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, type: string) { + await persistTrack(campaignId, processTrackTypes.staffMapping, processTrackStatuses.inprogress); + try { + logger.debug(`staff mapping count: ${mappingArray.length}`); + await processResourceOrFacilityOrUserMappingsInBatches(type, mappingArray, config?.batchSize || 100); + // 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)) + // } + // } + } 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); +} + +async function processResourceOrFacilityOrUserMappingsInBatches(type: string, mappingArray: any, batchSize: number) { + logger.info("Processing resource mappings in batches..."); + let promises: Promise[] = []; + let totalCreated = 0; // To keep track of the total number of created resources + let batchCount = 0; // To log batch-wise progress + // Determine the helper function to use based on the type + let createHelperFn: any; + if (type === 'resource') { + createHelperFn = createProjectResourceHelper; + } else if (type === 'staff') { + createHelperFn = createProjectStaffHelper; + } else if (type === 'facility') { + createHelperFn = createProjectFacilityHelper; + } else { + logger.error(`Unsupported type: ${type}`); + return; // Exit the function if the type is unsupported + } + + for (const mapping of mappingArray) { + const { resource, projectId, resouceBody, tenantId, startDate, endDate } = mapping; + + for (const resourceId of resource?.resourceIds || []) { + promises.push( + createHelperFn(resourceId, projectId, resouceBody, tenantId, startDate, endDate).then(() => { + totalCreated++; + }) + ); + + if (promises.length >= batchSize) { + batchCount++; + logger.info(`Processing batch ${batchCount} with ${promises.length} promises.`); + try { + await Promise.all(promises); // Wait for all promises in the current batch + } catch (error) { + logger.error(`Batch ${batchCount} failed:`, error); + throw error; // Ensure any error in the batch is propagated + } promises = []; // Reset the array for the next batch + } + } + } + + // Process any remaining promises + if (promises.length > 0) { + batchCount++; + logger.info(`Processing final batch ${batchCount} with ${promises.length} promises.`); + await Promise.all(promises); + } + + logger.info(`Processing completed. Total resources created: ${totalCreated}`); +} + + +export async function handleResourceMapping(mappingArray: any[], campaignId: any, messageObject: any, type: string) { + await persistTrack(campaignId, processTrackTypes.resourceMapping, processTrackStatuses.inprogress); + try { + logger.debug(`Resource mapping count: ${mappingArray.length}`); + await processResourceOrFacilityOrUserMappingsInBatches(type, mappingArray, config?.batchSize || 100); + } 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, type: string) { + await persistTrack(campaignId, processTrackTypes.facilityMapping, processTrackStatuses.inprogress); + try { + logger.debug(`facility mapping count: ${mappingArray.length}`); + // 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 processResourceOrFacilityOrUserMappingsInBatches(type, mappingArray, config?.batchSize || 100); + } 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, "resource"); + await handleFacilityMapping(facilityMappingArray, mappingObject?.CampaignDetails?.id, mappingObject, "facility"); + await handleStaffMapping(staffMappingArray, mappingObject?.CampaignDetails?.id, mappingObject, "staff"); + } + logger.info("Mapping completed successfully for campaign: " + mappingObject?.CampaignDetails?.id); + mappingObject.CampaignDetails.status = campaignStatuses.inprogress + if (mappingObject?.parentCampaign) { + await processResources(mappingObject); + mappingObject.CampaignDetails.campaignDetails.boundaries = [ + ...mappingObject.CampaignDetails.campaignDetails.boundaries, + ...mappingObject.parentCampaign.boundaries + ]; + } + 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..6a24266c28c 100644 --- a/health-services/project-factory/src/server/utils/campaignUtils.ts +++ b/health-services/project-factory/src/server/utils/campaignUtils.ts @@ -1,1825 +1,3800 @@ - import { defaultheader, httpRequest } from "./request"; import config from "../config/index"; -import { v4 as uuidv4 } from 'uuid'; -import { produceModifiedMessages } from '../kafka/Listener' -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 { v4 as uuidv4 } from "uuid"; +import { produceModifiedMessages } from "../kafka/Producer"; +import { + confirmProjectParentCreation, + createProjectCampaignResourcData, + getCampaignSearchResponse, + getHierarchy, + handleResouceDetailsError, + projectCreate, + projectUpdateForTargets, +} from "../api/campaignApis"; +import { + getCampaignNumber, + createAndUploadFile, + createExcelSheet, + getAutoGeneratedBoundaryCodesHandler, + createBoundaryEntities, + getMDMSV1Data, + getTargetSheetDataAfterCode, + callMdmsTypeSchema, + getSheetDataFromWorksheet, + getTargetWorkbook, + createAndUploadJsonFile, + createBoundaryRelationship, + getSheetData, +} 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"; +import { + addDataToSheet, + createBoundaryDataMainSheet, + createReadMeSheet, + findMapValue, + getBoundaryRelationshipData, + getConfigurableColumnHeadersFromSchemaForTargetSheet, + getLocalizedHeaders, + getLocalizedMessagesHandler, + getMdmsDataBasedOnCampaignType, + modifyBoundaryData, + replicateRequest, + throwError, +} from "./genericUtils"; import { enrichProjectDetailsFromCampaignDetails } from "./transforms/projectTypeUtils"; import { executeQuery } from "./db"; -import { campaignDetailsTransformer, genericResourceTransformer } from "./transforms/searchResponseConstructor"; +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"; -import { getExcelWorkbookFromFileURL, getNewExcelWorkbook, lockTargetFields, updateFontNameToRoboto } from "./excelUtils"; -const _ = require('lodash'); - - +import { + campaignStatuses, + headingMapping, + processTrackStatuses, + processTrackTypes, + resourceDataStatuses, +} from "../config/constants"; +import { getBoundaryTabName } from "./boundaryUtils"; +import { + searchProjectTypeCampaignService, + updateProjectTypeCampaignService, +} from "../service/campaignManageService"; +import { + validateBoundaryOfResouces, + validateBoundarySheetDataInCreateFlow, +} from "../validators/campaignValidators"; +import { + getExcelWorkbookFromFileURL, + getNewExcelWorkbook, + lockTargetFields, + updateFontNameToRoboto, +} from "./excelUtils"; +import { + areBoundariesSame, + callGenerate, + callGenerateIfBoundariesOrCampaignTypeDiffer, +} from "./generateUtils"; +import { createProcessTracks, persistTrack } from "./processTrackUtils"; +import { + generateDynamicTargetHeaders, + isDynamicTargetTemplateForProjectType, + updateTargetColumnsIfDeliveryConditionsDifferForSMC, +} from "./targetUtils"; +import { + callGenerateWhenChildCampaigngetsCreated, + fetchProjectsWithBoundaryCodeAndReferenceId, + fetchProjectsWithProjectId, + getBoundariesFromCampaignSearchResponse, + getBoundaryProjectMappingFromParentCampaign, + getColumnIndexByHeader, + hideColumnsOfProcessedFile, + modifyNewSheetData, + unhideColumnsOfProcessedFile, +} from "./onGoingCampaignUpdateUtils"; +import { changeCreateDataForMicroplan, lockSheet } from "./microplanUtils"; +const _ = require("lodash"); +import { searchDataService } from "../service/dataManageService"; +import { searchMDMSDataViaV2Api } from "../api/coreApis"; +import { deleteRedisCacheKeysWithPrefix } from "./redisUtils"; +import { + fetchFacilityData, + fetchTargetData, + fetchUserData, +} from "./microplanIntergration"; function updateRange(range: any, worksheet: 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++) { - const rowCells = worksheet.getRow(row + 1); // ExcelJS rows are 1-based - rowCells.eachCell((cell: any, colNumber: number) => { - if (cell.value !== undefined && colNumber > maxColumnIndex) { - maxColumnIndex = colNumber; - } - }); - } + 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++) { + const rowCells = worksheet.getRow(row + 1); // ExcelJS rows are 1-based + rowCells.eachCell((cell: any, colNumber: number) => { + if (cell.value !== undefined && colNumber > maxColumnIndex) { + maxColumnIndex = colNumber; + } + }); + } - // Update the end column of the range with the maximum column index found - range.e.c = maxColumnIndex; + // Update the end column of the range with the maximum column index found + range.e.c = maxColumnIndex; } function findAndChangeColumns(worksheet: any, columns: any) { - const firstRow = worksheet.getRow(1); // First row (ExcelJS is 1-based) - firstRow.eachCell((cell: any, colNumber: number) => { - if (cell.value === '#status#') { - columns.statusColumn = cell.address.replace(/\d+/g, ''); - // Set the cell color to green - cell.fill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: 'CCCC00' } - }; - // Delete status column cells in subsequent rows - worksheet.eachRow((row: any, rowIndex: number) => { - if (rowIndex > 1) { - const statusCell = row.getCell(colNumber); - statusCell.value = undefined; - } - }); + const firstRow = worksheet.getRow(1); + firstRow.eachCell((cell: any, colNumber: number) => { + if (cell.value === "#status#") { + columns.statusColumn = cell.address.replace(/\d+/g, ""); + // Set the cell color to green + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "CCCC00" }, + }; + // Delete status column cells in subsequent rows + worksheet.eachRow((row: any, rowIndex: number) => { + if (rowIndex > 1) { + const statusCell = row.getCell(colNumber); + statusCell.value = undefined; } - if (cell.value === '#errorDetails#') { - columns.errorDetailsColumn = cell.address.replace(/\d+/g, ''); - // Set the cell color to green - cell.fill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: 'CCCC00' } - }; - // Delete error details column cells in subsequent rows - worksheet.eachRow((row: any, rowIndex: number) => { - if (rowIndex > 1) { - const errorDetailsCell = row.getCell(colNumber); - errorDetailsCell.value = undefined; - } - }); + }); + } + if (cell.value === "#errorDetails#") { + columns.errorDetailsColumn = cell.address.replace(/\d+/g, ""); + // Set the cell color to green + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "CCCC00" }, + }; + // Delete error details column cells in subsequent rows + worksheet.eachRow((row: any, rowIndex: number) => { + if (rowIndex > 1) { + const errorDetailsCell = row.getCell(colNumber); + errorDetailsCell.value = undefined; } - }); + }); + } + }); } function makeColumns(worksheet: any, range: any, columns: any) { - // If the status column doesn't exist, calculate the next available column - if (!columns?.statusColumn) { - const emptyColumnIndex = range.e.c; - columns.statusColumn = String.fromCharCode(65 + (emptyColumnIndex + 1)); - const statusCell = worksheet.getCell(`${columns.statusColumn}1`); - statusCell.value = '#status#'; - statusCell.fill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: 'CCCC00' } - }; - statusCell.font = { bold: true }; - } - - // Calculate errorDetails column one column to the right of status column - if (!columns?.errorDetailsColumn) { - columns.errorDetailsColumn = String.fromCharCode(columns?.statusColumn.charCodeAt(0) + 1); - const errorDetailsCell = worksheet.getCell(`${columns.errorDetailsColumn}1`); - errorDetailsCell.value = '#errorDetails#'; - errorDetailsCell.fill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: 'CCCC00' } - }; - errorDetailsCell.font = { bold: true }; - } + // If the status column doesn't exist, calculate the next available column + if (!columns?.statusColumn) { + const emptyColumnIndex = range.e.c; + columns.statusColumn = String.fromCharCode(65 + (emptyColumnIndex + 1)); + const statusCell = worksheet.getCell(`${columns.statusColumn}1`); + statusCell.value = "#status#"; + statusCell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "CCCC00" }, + }; + statusCell.font = { bold: true }; + worksheet.getColumn(columns.statusColumn).width = 40; + } + + // Calculate errorDetails column one column to the right of status column + if (!columns?.errorDetailsColumn) { + columns.errorDetailsColumn = String.fromCharCode( + columns?.statusColumn.charCodeAt(0) + 1 + ); + const errorDetailsCell = worksheet.getCell( + `${columns.errorDetailsColumn}1` + ); + errorDetailsCell.value = "#errorDetails#"; + errorDetailsCell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "CCCC00" }, + }; + errorDetailsCell.font = { bold: true }; + worksheet.getColumn(columns.errorDetailsColumn).width = 40; + } } - function findColumns(worksheet: any) { - const range = { - s: { r: 0, c: 0 }, - e: { r: worksheet.rowCount - 1, c: worksheet.columnCount - 1 } - }; + const range = { + s: { r: 0, c: 0 }, + e: { r: worksheet.rowCount - 1, c: worksheet.columnCount - 1 }, + }; - // Check if the status column already exists in the first row - var columns = {} + // Check if the status column already exists in the first row + var columns = {}; - findAndChangeColumns(worksheet, columns); + findAndChangeColumns(worksheet, columns); - makeColumns(worksheet, range, columns); + makeColumns(worksheet, range, columns); - updateRange(range, worksheet); + updateRange(range, worksheet); - return columns; + return columns; } -function enrichErrors(errorData: any, worksheet: any, statusColumn: any, errorDetailsColumn: any, additionalDetailsErrors: any, createAndSearchConfig: any, localizationMap?: { [key: string]: string }) { - if (errorData) { - errorData.forEach((error: any) => { - const rowIndex = error.rowNumber; // ExcelJS rows are 1-based - const statusCell = worksheet.getCell(`${statusColumn}${rowIndex}`); - const errorDetailsCell = worksheet.getCell(`${errorDetailsColumn}${rowIndex}`); - statusCell.value = error.status; - errorDetailsCell.value = error.errorDetails; - - if ((error?.status) && !(error?.status === "CREATED" || error?.status === "VALID")) { - additionalDetailsErrors.push(error); - } - }); - if (errorData.some((error: any) => error?.status === "CREATED")) { - const uniqueIdentifierFirstRowCell = `${createAndSearchConfig?.uniqueIdentifierColumn}1`; - const columnName = getLocalizedName(createAndSearchConfig?.uniqueIdentifierColumnName, localizationMap); - const uniqueIdentifierCell = worksheet.getCell(uniqueIdentifierFirstRowCell); - uniqueIdentifierCell.value = columnName; - - // Set the cell color to green - uniqueIdentifierCell.fill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: 'ff9248' } // Green color - }; - uniqueIdentifierCell.font = { bold: true }; - // Hide the unique identifier column - worksheet.getColumn(createAndSearchConfig?.uniqueIdentifierColumn).hidden = true; - } - errorData.forEach((error: any) => { - const rowIndex = error.rowNumber; - if (error.isUniqueIdentifier) { - const uniqueIdentifierCell = worksheet.getCell(`${createAndSearchConfig.uniqueIdentifierColumn}${rowIndex}`); - uniqueIdentifierCell.value = error.uniqueIdentifier; - if (createAndSearchConfig?.activeColumn) { - const activeCell = worksheet.getCell(`${createAndSearchConfig.activeColumn}${rowIndex}`); - activeCell.value = "Active"; - } - } - }); - } -} - -function enrichActiveColumn(worksheet: any, createAndSearchConfig: any, request: any) { - if (createAndSearchConfig?.activeColumn && request?.body?.dataToCreate) { - const dataToCreate = request.body.dataToCreate; - for (const data of dataToCreate) { - const rowNumber = data['!row#number!']; - const activeCell = worksheet.getCell(`${createAndSearchConfig?.activeColumn}${rowNumber}`); - activeCell.value = "Active"; +function enrichErrors( + errorData: any, + worksheet: any, + statusColumn: any, + errorDetailsColumn: any, + additionalDetailsErrors: any, + createAndSearchConfig: any, + localizationMap?: { [key: string]: string } +) { + if (errorData) { + errorData.forEach((error: any) => { + const rowIndex = error.rowNumber; // ExcelJS rows are 1-based + const statusCell = worksheet.getCell(`${statusColumn}${rowIndex}`); + const errorDetailsCell = worksheet.getCell( + `${errorDetailsColumn}${rowIndex}` + ); + statusCell.value = error.status; + errorDetailsCell.value = error.errorDetails; + + if ( + error?.status && + !(error?.status === "CREATED" || error?.status === "VALID") + ) { + additionalDetailsErrors.push(error); + } + }); + if (errorData.some((error: any) => error?.status === "CREATED")) { + const uniqueIdentifierFirstRowCell = `${createAndSearchConfig?.uniqueIdentifierColumn}1`; + const columnName = getLocalizedName( + createAndSearchConfig?.uniqueIdentifierColumnName, + localizationMap + ); + const uniqueIdentifierCell = worksheet.getCell( + uniqueIdentifierFirstRowCell + ); + uniqueIdentifierCell.value = columnName; + + // Set the cell color to green + uniqueIdentifierCell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "ff9248" }, // Green color + }; + uniqueIdentifierCell.font = { bold: true }; + // Hide the unique identifier column + worksheet.getColumn( + createAndSearchConfig?.uniqueIdentifierColumn + ).hidden = true; + } + errorData.forEach((error: any) => { + const rowIndex = error.rowNumber; + if (error.isUniqueIdentifier) { + const uniqueIdentifierCell = worksheet.getCell( + `${createAndSearchConfig.uniqueIdentifierColumn}${rowIndex}` + ); + uniqueIdentifierCell.value = error.uniqueIdentifier; + if (createAndSearchConfig?.activeColumn) { + const activeCell = worksheet.getCell( + `${createAndSearchConfig.activeColumn}${rowIndex}` + ); + activeCell.value = "Active"; } - } -} - -function deterMineLastColumnAndEnrichUserDetails(worksheet: any, errorDetailsColumn: any, userNameAndPassword: any, request: any, createAndSearchConfig: any) { - let lastColumn = errorDetailsColumn; - if (createAndSearchConfig?.uniqueIdentifierColumn !== undefined) { - lastColumn = createAndSearchConfig?.uniqueIdentifierColumn > errorDetailsColumn ? - createAndSearchConfig?.uniqueIdentifierColumn : - errorDetailsColumn; - } - - if (userNameAndPassword) { - worksheet.getCell("I1").value = "UserName"; - worksheet.getCell("J1").value = "Password"; - - // Set the fill color to green for cell I1 - worksheet.getCell("I1").fill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: 'ff9248' } // Green color - }; - worksheet.getCell("I1").font = { bold: true }; - - // Set the fill color to green for cell J1 - worksheet.getCell("J1").fill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: 'ff9248' } // Green color - }; - worksheet.getCell("J1").font = { bold: true }; - - userNameAndPassword.forEach((data: any) => { - const rowIndex = data.rowNumber; - worksheet.getCell(`I${rowIndex}`).value = data?.userName; - worksheet.getCell(`J${rowIndex}`).value = data?.password; - }); - - lastColumn = "J"; - request.body.userNameAndPassword = undefined; - } - - return lastColumn; + } + }); + } } -function adjustRef(worksheet: any, lastColumn: any) { - const range = worksheet.getSheetValues().filter((row: any) => row).length; // Get the number of used rows - worksheet.views = [ - { state: 'frozen', ySplit: 1, topLeftCell: 'A2', activeCell: 'A2' } - ]; - worksheet.autoFilter = { - from: { - row: 1, - column: 1 - }, - to: { - row: range, - column: worksheet.getColumn(lastColumn).number - } +function enrichActiveAndUUidColumn( + worksheet: any, + createAndSearchConfig: any, + request: any +) { + if ( + createAndSearchConfig?.activeColumn && + request?.body?.dataToCreate && + request?.body?.dataToCreate?.length > 0 && + request?.body?.ResourceDetails?.type == "user" + ) { + const dataToCreate = request.body.dataToCreate; + for (const data of dataToCreate) { + const rowNumber = data["!row#number!"]; + const activeCell = worksheet.getCell( + `${createAndSearchConfig?.activeColumn}${rowNumber}` + ); + const uniqueIdentifierCell = worksheet.getCell( + `${createAndSearchConfig?.uniqueIdentifierColumn}${rowNumber}` + ); + activeCell.value = "Active"; + uniqueIdentifierCell.value = data["userServiceUuid"]; + } + } +} + +function deterMineLastColumnAndEnrichUserDetails( + worksheet: any, + errorDetailsColumn: number, + userNameAndPassword: + | { rowNumber: number; userName: string; password: string }[] + | undefined, + request: any, + createAndSearchConfig: { uniqueIdentifierColumn?: number } +): string { + // Determine the last column + let lastColumn: any = errorDetailsColumn; + if (createAndSearchConfig?.uniqueIdentifierColumn !== undefined) { + lastColumn = + createAndSearchConfig?.uniqueIdentifierColumn > errorDetailsColumn + ? createAndSearchConfig?.uniqueIdentifierColumn + : errorDetailsColumn; + } + + // Default columns + let usernameColumn = "J"; + let passwordColumn = "K"; + + // Update columns if the request indicates a different source + if ( + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" + ) { + usernameColumn = "F"; + passwordColumn = "G"; + } + + // Populate username and password columns if data is provided + if (userNameAndPassword) { + // Set headers with formatting + const setCellHeader = (cell: string) => { + worksheet.getCell(cell).value = + cell === usernameColumn + "1" ? "UserName" : "Password"; + worksheet.getCell(cell).fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "ff9248" }, // Green color + }; + worksheet.getCell(cell).font = { bold: true }; + const columnLetter = cell.replace(/\d+$/, ""); + worksheet.getColumn(columnLetter).width = 40; }; -} - -function processErrorData(request: any, createAndSearchConfig: any, workbook: any, sheetName: any, localizationMap?: { [key: string]: string }) { - const worksheet = workbook.getWorksheet(sheetName); - const errorData = request.body.sheetErrorDetails; - const userNameAndPassword = request.body.userNameAndPassword; - const columns: any = findColumns(worksheet); - const statusColumn = columns.statusColumn; - const errorDetailsColumn = columns.errorDetailsColumn; - const additionalDetailsErrors: any[] = []; - - enrichErrors(errorData, worksheet, statusColumn, errorDetailsColumn, additionalDetailsErrors, createAndSearchConfig, localizationMap); - enrichActiveColumn(worksheet, createAndSearchConfig, request); - - request.body.additionalDetailsErrors = additionalDetailsErrors; - - // Determine the last column to set the worksheet ref - const lastColumn = deterMineLastColumnAndEnrichUserDetails(worksheet, errorDetailsColumn, userNameAndPassword, request, createAndSearchConfig); - - // Adjust the worksheet ref to include the last column - adjustRef(worksheet, lastColumn); - updateFontNameToRoboto(worksheet) - - workbook.xlsx.writeBuffer(); -} - - -function processErrorDataForTargets(request: any, createAndSearchConfig: any, workbook: any, sheetName: any) { - const desiredSheet = workbook.getWorksheet(sheetName); - const columns: any = findColumns(desiredSheet); - const statusColumn = columns.statusColumn; - const errorDetailsColumn = columns.errorDetailsColumn; - - const errorData = request.body.sheetErrorDetails.filter((error: any) => error.sheetName === sheetName); - const additionalDetailsErrors: any = []; - - if (errorData) { - errorData.forEach((error: any) => { - const rowIndex = error.rowNumber; - if (error.isUniqueIdentifier) { - const uniqueIdentifierCell = createAndSearchConfig.uniqueIdentifierColumn + (rowIndex); - desiredSheet.getCell(uniqueIdentifierCell).value = error.uniqueIdentifier; - } - - const statusCell = statusColumn + (rowIndex); - const errorDetailsCell = errorDetailsColumn + (rowIndex); - desiredSheet.getCell(statusCell).value = error.status; - desiredSheet.getCell(errorDetailsCell).value = error.errorDetails; - if (!(error.status === "CREATED" || error.status === "VALID")) { - additionalDetailsErrors.push(error); - } - }); - } - - request.body.additionalDetailsErrors = additionalDetailsErrors; - updateFontNameToRoboto(desiredSheet) - workbook.worksheets[sheetName] = desiredSheet; -} + setCellHeader(usernameColumn + "1"); + setCellHeader(passwordColumn + "1"); -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 fileUrl = fileResponse?.fileStoreIds?.[0]?.url; - const sheetName = createAndSearchConfig?.parseArrayConfig?.sheetName; - const localizedSheetName = getLocalizedName(sheetName, localizationMap); - const workbook: any = await getExcelWorkbookFromFileURL(fileUrl, localizedSheetName); - const worksheet: any = workbook.getWorksheet(localizedSheetName); - processErrorData(request, createAndSearchConfig, workbook, localizedSheetName, localizationMap); - - // Set column widths - const columnWidths = Array(12).fill({ width: 30 }); - columnWidths.forEach((colWidth, index) => { - if (worksheet.getColumn(index + 1)) { - worksheet.getColumn(index + 1).width = colWidth.width; - } + // Set values + userNameAndPassword.forEach((data) => { + const rowIndex = data.rowNumber; + worksheet.getCell(`${usernameColumn}${rowIndex}`).value = data.userName; + worksheet.getCell(`${passwordColumn}${rowIndex}`).value = data.password; }); - const responseData = await createAndUploadFile(workbook, request); + // Update lastColumn based on the password column + lastColumn = passwordColumn; + } - 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"); - } + return lastColumn; } -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 fileUrl = fileResponse?.fileStoreIds?.[0]?.url; - - const workbook: any = await getExcelWorkbookFromFileURL(fileUrl, ""); - const sheetNames = workbook.worksheets.map((worksheet: any) => worksheet.name); - 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; +function adjustRef(worksheet: any, lastColumn: any) { + 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" }, + ]; + worksheet.autoFilter = { + from: { + row: 1, + column: 1, + }, + to: { + row: range, + column: worksheet.getColumn(lastColumn).number, + }, + }; +} + +function processErrorData( + request: any, + createAndSearchConfig: any, + workbook: any, + sheetName: any, + localizationMap?: { [key: string]: string } +) { + const worksheet = workbook.getWorksheet(sheetName); + var errorData = request.body.sheetErrorDetails; + const userNameAndPassword = request.body.userNameAndPassword; + const columns: any = findColumns(worksheet); + const statusColumn = columns.statusColumn; + const errorDetailsColumn = columns.errorDetailsColumn; + const additionalDetailsErrors: any[] = []; + errorData = mergeErrors(errorData); + enrichErrors( + errorData, + worksheet, + statusColumn, + errorDetailsColumn, + additionalDetailsErrors, + createAndSearchConfig, + localizationMap + ); + enrichActiveAndUUidColumn(worksheet, createAndSearchConfig, request); + + request.body.additionalDetailsErrors = request?.body?.additionalDetailsErrors + ? request?.body?.additionalDetailsErrors.concat(additionalDetailsErrors) + : additionalDetailsErrors; + + // Determine the last column to set the worksheet ref + const lastColumn = deterMineLastColumnAndEnrichUserDetails( + worksheet, + errorDetailsColumn, + userNameAndPassword, + request, + createAndSearchConfig + ); + + // Adjust the worksheet ref to include the last column + adjustRef(worksheet, lastColumn); + updateFontNameToRoboto(worksheet); + + workbook.xlsx.writeBuffer(); +} + +function mergeErrors(errorData: any) { + const errorMap: any = {}; + + errorData.forEach((item: any) => { + const { rowNumber, sheetName, status, errorDetails, ...rest } = item; + + // If the rowNumber already exists, merge the errorDetails + if (errorMap[rowNumber]) { + errorMap[rowNumber].errorDetails += "; " + errorDetails; } else { - throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); - } + // If not, add a new entry + errorMap[rowNumber] = { + rowNumber, + sheetName, + status, + errorDetails, + ...rest, + }; + } + }); + + // Convert the errorMap back into an array + return Object.values(errorMap); +} + +function processErrorDataForEachSheets( + request: any, + createAndSearchConfig: any, + workbook: any, + sheetName: any +) { + const desiredSheet = workbook.getWorksheet(sheetName); + const columns: any = findColumns(desiredSheet); + const statusColumn = columns.statusColumn; + const errorDetailsColumn = columns.errorDetailsColumn; + const userNameAndPassword = request?.body?.userNameAndPassword; + + var errorData = request.body.sheetErrorDetails.filter( + (error: any) => error.sheetName === sheetName + ); + const additionalDetailsErrors: any = []; + errorData = mergeErrors(errorData); + if (errorData) { + errorData.forEach((error: any) => { + const rowIndex = error.rowNumber; + if (error.isUniqueIdentifier) { + const uniqueIdentifierCell = + createAndSearchConfig.uniqueIdentifierColumn + rowIndex; + desiredSheet.getCell(uniqueIdentifierCell).value = + error.uniqueIdentifier; + } + + const statusCell = statusColumn + rowIndex; + const errorDetailsCell = errorDetailsColumn + rowIndex; + desiredSheet.getCell(statusCell).value = error.status; + desiredSheet.getCell(errorDetailsCell).value = error.errorDetails; + + if (!(error.status === "CREATED" || error.status === "VALID")) { + additionalDetailsErrors.push(error); + } + }); + } + if (userNameAndPassword) { + var newUserNameAndPassword: any = []; + for (const data of userNameAndPassword) { + const rowArray = data.rowNumber; + for (let i = 0; i < rowArray.length; i++) { + if (rowArray[i].sheetName == sheetName) { + newUserNameAndPassword.push({ ...data, rowNumber: rowArray[i].row }); + } + } + } + } + deterMineLastColumnAndEnrichUserDetails( + desiredSheet, + errorDetailsColumn, + newUserNameAndPassword, + request, + createAndSearchConfig + ); + request.body.additionalDetailsErrors = request?.body?.additionalDetailsErrors + ? request?.body?.additionalDetailsErrors.concat(additionalDetailsErrors) + : additionalDetailsErrors; + updateFontNameToRoboto(desiredSheet); + workbook.worksheets[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" + ); + const isLockSheetNeeded = + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" + ? true + : false; + + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 500, "INVALID_FILE"); + } + const fileUrl = fileResponse?.fileStoreIds?.[0]?.url; + const sheetName = createAndSearchConfig?.parseArrayConfig?.sheetName; + const localizedSheetName = getLocalizedName(sheetName, localizationMap); + const workbook: any = await getExcelWorkbookFromFileURL( + fileUrl, + localizedSheetName + ); + const worksheet: any = workbook.getWorksheet(localizedSheetName); + if (request?.body?.ResourceDetails?.type == "user") { + const columnsToUnhide = ["G", "H", "J", "K"]; + unhideColumnsOfProcessedFile(worksheet, columnsToUnhide); + } + processErrorData( + request, + createAndSearchConfig, + workbook, + localizedSheetName, + localizationMap + ); + + // Set column widths + const columnWidths = Array(12).fill({ width: 30 }); + columnWidths.forEach((colWidth, index) => { + if (worksheet.getColumn(index + 1)) { + worksheet.getColumn(index + 1).width = colWidth.width; + } + }); + if (isLockSheetNeeded) lockSheet(request, workbook); + 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 updateStatusFileForEachSheets( + 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" + ); + const isLockSheetNeeded = + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" + ? true + : false; + + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 500, "INVALID_FILE"); + } + + const fileUrl = fileResponse?.fileStoreIds?.[0]?.url; + + const workbook: any = await getExcelWorkbookFromFileURL(fileUrl, ""); + + const sheetNames = workbook.worksheets.map( + (worksheet: any) => worksheet.name + ); + const localizedSheetNames = getLocalizedHeaders(sheetNames, localizationMap); + + const sheetErrorDetails = request?.body?.sheetErrorDetails; + if (sheetErrorDetails && sheetErrorDetails?.length > 0) { + const firstError = sheetErrorDetails[0]; + if (Array.isArray(firstError?.rowNumber)) { + var newSheetErrorDetails: any = []; + for (const error of sheetErrorDetails) { + for (let i = 0; i < error.rowNumber.length; i++) { + newSheetErrorDetails.push({ + ...error, + rowNumber: error.rowNumber[i]?.row, + sheetName: error.rowNumber[i]?.sheetName, + }); + } + } + request.body.sheetErrorDetails = newSheetErrorDetails; + } + } + + localizedSheetNames.forEach((sheetName: any) => { + if ( + sheetName !== + getLocalizedName(config?.boundary?.boundaryTab, localizationMap) && + sheetName !== + getLocalizedName(config.values.readMeTab, localizationMap) && + sheetName !== + getLocalizedName("USER_MICROPLAN_SHEET_ROLES", localizationMap) + ) { + processErrorDataForEachSheets( + request, + createAndSearchConfig, + workbook, + sheetName + ); + } + }); + if (isLockSheetNeeded) lockSheet(request, workbook); + 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; - } + 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 + 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); - } + 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; + const isSourceMicroplan = + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan"; + 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]; } - 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 (element.type) { + dataToSet = convertToType(dataToSet, element.type); } - if (addToCreate) { - createData.push(resultantElement) + _.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]) { + if (isSourceMicroplan) { + changeCreateDataForMicroplan( + request, + resultantElement, + data, + localizationMap + ); + } + searchData.push(resultantElement); + addToCreate = false; + break; } - } - 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; + } + } + if (addToCreate) { + if (isSourceMicroplan) { + changeCreateDataForMicroplan( + request, + resultantElement, + data, + localizationMap + ); + } + 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); +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 - } + 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 } || {} +async function generateProcessedFileAndPersist( + request: any, + localizationMap?: { [key: string]: string } +) { + if ( + request.body.ResourceDetails.type == "boundaryWithTarget" || + (request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" && + request.body.ResourceDetails.type == "user") + ) { + await updateStatusFileForEachSheets(request, localizationMap); + } else { + if ( + request.body.ResourceDetails.type !== "boundary" && + request.body.ResourceDetails.type !== "boundaryManagement" + ) { + 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, + source: + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" + ? "microplan" + : null, + }, + }; + if ( + request?.body?.ResourceDetails?.status === resourceDataStatuses.completed && + request?.body?.ResourceDetails?.type === "boundaryManagement" + ) { + // delete redis cache key with prefix boundaryRelatiionshipSearch + await deleteRedisCacheKeysWithPrefix("boundaryRelationShipSearch"); + + logger.info( + "calling generate after boundary data uploaded under type boundary management" + ); + const newRequestBody = { + RequestInfo: request?.body?.RequestInfo, }; - const persistMessage: any = { ResourceDetails: request.body.ResourceDetails } - if (request?.body?.ResourceDetails?.action == "create") { - persistMessage.ResourceDetails.additionalDetails = {} - } - 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)) { - 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 params = { + type: request?.body?.ResourceDetails?.type, + tenantId: request?.body?.ResourceDetails?.tenantId, + forceUpdate: "true", + hierarchyType: request?.body?.ResourceDetails?.hierarchyType, + campaignId: "default", + }; + const newRequestBoundary = replicateRequest( + request, + newRequestBody, + params + ); + setTimeout(async () => { + // Code to be executed after 10 seconds + logger.info("Timeout of 10 sec after boundary data creation"); + await callGenerate( + newRequestBoundary, + request?.body?.ResourceDetails?.type + ); + }, 10000); + } + const persistMessage: any = { ResourceDetails: request.body.ResourceDetails }; + if (request?.body?.ResourceDetails?.action == "create") { + persistMessage.ResourceDetails.additionalDetails = { + source: + request?.body?.ResourceDetails?.additionalDetails?.source == "microplan" + ? "microplan" + : null, + fileName: + request?.body?.ResourceDetails?.additionalDetails?.fileName || null, + }; + } + 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 + ) { + logger.info("Activities to persist : "); + logger.debug(getFormattedStringForDebug(request?.body?.Activities)); + logger.info(`Waiting for 2 seconds`); + await new Promise((resolve) => setTimeout(resolve, 2000)); + const activities = request?.body?.Activities; + for (let i = 0; i < activities.length; i += 10) { + const chunk = activities.slice(i, Math.min(i + 10, activities.length)); + const activityObject: any = { Activities: chunk }; + await produceModifiedMessages( + activityObject, + config.kafka.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC + ); + } + } } function getRootBoundaryCode(boundaries: any[] = []) { - for (const boundary of boundaries) { - if (boundary.isRoot) { - return boundary.code; - } + for (const boundary of boundaries) { + if (boundary.isRoot) { + return boundary.code; } - return ""; + } + return ""; } function enrichRootProjectId(requestBody: any) { - var rootBoundary; - for (const boundary of requestBody?.CampaignDetails?.boundaries) { - if (boundary?.isRoot) { - rootBoundary = boundary?.code - break; - } + var rootBoundary; + for (const boundary of requestBody?.boundariesCombined) { + if (boundary?.isRoot) { + rootBoundary = boundary?.code; + break; } - if (rootBoundary) { - requestBody.CampaignDetails.projectId = requestBody?.boundaryProjectMapping?.[rootBoundary]?.projectId || null - } - requestBody.CampaignDetails.projectId = requestBody.CampaignDetails.projectId || null + } + 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 == "changeDates" ? 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 + if (requestBody?.parentCampaign) { + await makeParentInactiveOrActive(requestBody, true); + } + 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.isActive = false; + requestBody.CampaignDetails.boundaryCode = + getRootBoundaryCode(requestBody?.boundariesCombined) || 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?.description}` : "") || + error + ), + }; + const topic = config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_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; +} + +async function enrichAndPersistCampaignForCreate( + request: any, + firstPersist: boolean = false +) { + const action = request?.body?.CampaignDetails?.action; + if (firstPersist) { + if (!request?.body?.parentCampaign) { + request.body.CampaignDetails.campaignNumber = await getCampaignNumber( + request.body, + "CMP-[cy:yyyy-MM-dd]-[SEQ_EG_CMP_ID]", + "campaign.number", + request?.body?.CampaignDetails?.tenantId + ); + } else { + request.body.CampaignDetails.campaignNumber = + request.body.parentCampaign?.campaignNumber; + request.body.CampaignDetails.campaignName = + request.body.parentCampaign?.campaignName; + } + } + 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?.boundariesCombined + ); + 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; + const produceMessage: any = { + CampaignDetails: request?.body?.CampaignDetails, + }; + await produceModifiedMessages(produceMessage, 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 || []; } -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..."); - logger.debug(`CampaignProjectMapping: ${getFormattedStringForDebug(requestBody)}`); - produceModifiedMessages(requestBody, config?.kafka?.KAFKA_START_CAMPAIGN_MAPPING_TOPIC); - } +async function enrichAndPersistCampaignForUpdate( + request: any, + firstPersist: boolean = false +) { + const action = request?.body?.CampaignDetails?.action; + const boundaries = request?.body?.boundariesCombined; + const existingCampaignDetails = request?.body?.ExistingCampaignDetails; + callGenerateIfBoundariesOrCampaignTypeDiffer(request); + if (existingCampaignDetails) { + if (areBoundariesSame(existingCampaignDetails?.boundaries, boundaries)) { + updateTargetColumnsIfDeliveryConditionsDifferForSMC(request); + } + } + 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 == "changeDates" + ? request.body.CampaignDetails.status + : action == "create" + ? campaignStatuses.started + : campaignStatuses.drafted; + const boundaryCode = !request?.body?.CampaignDetails?.projectId + ? getRootBoundaryCode(request.body?.boundariesCombined) + : 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; + 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; +} + +async function makeParentInactiveOrActive(requestBody: any, active: boolean) { + let parentCampaign = requestBody?.parentCampaign; + parentCampaign.isActive = active; + parentCampaign.campaignDetails = { + deliveryRules: parentCampaign?.deliveryRules || [], + resources: parentCampaign?.resources || [], + boundaries: parentCampaign?.boundaries || [], + }; + parentCampaign.auditDetails.lastModifiedTime = Date.now(); + parentCampaign.auditDetails.lastModifiedBy = + requestBody?.RequestInfo?.userInfo?.uuid; + const produceMessage: any = { + CampaignDetails: parentCampaign, + }; + await produceModifiedMessages( + produceMessage, + config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_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) - } +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 enrichAndPersistProjectCampaignForFirst(request: any, actionInUrl: any, firstPersist: boolean = false, localizationMap?: any) { - removeBoundariesFromRequest(request); - if (actionInUrl == "create") { - await enrichAndPersistCampaignForCreate(request, firstPersist) - } - else if (actionInUrl == "update") { - await enrichAndPersistCampaignForUpdate(request, firstPersist) - } +async function persistForCampaignProjectMapping( + request: any, + createResourceDetailsIds: any, + localizationMap?: any +) { + if (createResourceDetailsIds && request?.body?.CampaignDetails?.projectId) { + var requestBody: any = { + RequestInfo: request?.body?.RequestInfo, + Campaign: {}, + }; + if (request?.body?.ExistingCampaignDetails) { + delete request.body.ExistingCampaignDetails; + } + requestBody.Campaign.id = request?.body?.CampaignDetails?.id; + // requestBody.Campaign.newlyCreatedBoundaryProjectMap = + // request?.body?.newlyCreatedBoundaryProjectMap; + 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; + requestBody.parentCampaign = request?.body?.parentCampaign; + var updatedInnerCampaignDetails = {}; + enrichInnerCampaignDetails(request, updatedInnerCampaignDetails); + requestBody.CampaignDetails = request?.body?.CampaignDetails; + requestBody.CampaignDetails.campaignDetails = updatedInnerCampaignDetails; + // requestBody.localizationMap = localizationMap + logger.info("Persisting CampaignProjectMapping..."); + logger.debug( + `CampaignProjectMapping: ${getFormattedStringForDebug(requestBody)}` + ); + await produceModifiedMessages( + requestBody, + config?.kafka?.KAFKA_START_CAMPAIGN_MAPPING_TOPIC + ); + } } +function removeBoundariesFromRequest(request: any) { + const boundaries = request?.body?.CampaignDetails?.boundaries; + if (boundaries && Array.isArray(boundaries) && boundaries?.length > 0) { + request.body.CampaignDetails.boundaries = 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); - } +async function enrichAndPersistProjectCampaignForFirst( + request: any, + actionInUrl: any, + firstPersist: boolean = false, + localizationMap?: any +) { + removeBoundariesFromRequest(request); + if (actionInUrl == "create") { + await enrichAndPersistCampaignForCreate(request, firstPersist); + } else if (actionInUrl == "update") { + await enrichAndPersistCampaignForUpdate(request, firstPersist); + } + if (request?.body?.parentCampaign?.isActive) { + await makeParentInactiveOrActive(request?.body, false); + } + if (request?.body?.CampaignDetails?.action == "create") { + await createProcessTracks(request.body.CampaignDetails.id); + } +} + +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; + 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); - } - } + 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; + } } - mappingMap.set(row[len - 2], row[len - 1].value); - }); - return { mappingMap, countMap }; + 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 +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; } + }); } - 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++; - } - } + ); + + 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; +} - let query = ` +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(campaignDetails: any) { + 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 ${config?.DB_CONFIG.DB_CAMPAIGN_DETAILS_TABLE_NAME} 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 = ` + 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; + } else { + // If no IDs are provided, filter by isActive = true + query += ` AND isActive = true`; + } + 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); + return totalCount; +} + +async function searchProjectCampaignResourcData(campaignDetails: any) { + // const CampaignDetails = request.body.CampaignDetails; + const { tenantId, pagination, ids, ...searchFields } = campaignDetails; + const queryData = buildSearchQuery(tenantId, pagination, ids, searchFields); + const totalCount = await getTotalCount(campaignDetails); + 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; + } + return { responseData, totalCount }; +} + +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 ${config?.DB_CONFIG.DB_CAMPAIGN_DETAILS_TABLE_NAME} 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; - } + 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; + } else { + // If no IDs are provided, filter by isActive = true + query += ` AND isActive = true`; + } - 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); + 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 (conditions.length > 0) { + query += ` AND ${conditions.join(" AND ")}`; + } - if (pagination) { - query += '\n'; + if (pagination) { + query += "\n"; - if (pagination.sortBy) { - query += `ORDER BY ${pagination.sortBy}`; - if (pagination.sortOrder) { - query += ` ${pagination.sortOrder.toUpperCase()}`; - } - 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'; - } + if (pagination.limit !== undefined) { + query += `LIMIT ${pagination.limit}`; + if (pagination.offset !== undefined) { + query += ` OFFSET ${pagination.offset}`; + } + query += "\n"; } + } - return { query, values }; + return { query, values }; } - - async function executeSearchQuery(query: string, values: any[]) { - const queryResult = await executeQuery(query, values); - return campaignDetailsTransformer(queryResult?.rows); + 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 ${config?.DB_CONFIG.DB_RESOURCE_DETAILS_TABLE_NAME} - ${whereClause};`, values - }; + 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, hierarchyType } = SearchCriteria; + let conditions = []; + let values = []; + + // Check for id + if (id && id.length > 0) { + conditions.push(`id = ANY($${values.length + 1})`); + values.push(id); + } + + // Check for tenantId + if (tenantId) { + conditions.push(`tenantId = $${values.length + 1}`); + values.push(tenantId); + } + + // Check for type + if (type) { + conditions.push(`type = $${values.length + 1}`); + values.push(type); + } + + // Check for status + if (status) { + conditions.push(`status = $${values.length + 1}`); + values.push(status); + } + + // Check for hierarchyType + if (hierarchyType) { + conditions.push(`hierarchyType = $${values.length + 1}`); + values.push(hierarchyType); + } + + // Build the WHERE clause + const whereClause = + conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : ""; + + // Return the query and values array + return { + query: ` + SELECT * + FROM ${config?.DB_CONFIG.DB_RESOURCE_DETAILS_TABLE_NAME} + ${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; + if (!boundaryResponse) 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); + 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); } + } } - -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); - } - } - } +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 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 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?.boundariesCombined; + var boundaryCodes = new Set(boundaries.map((boundary: any) => boundary.code)); + await processBoundary( + boundaryResponse, + boundaries, + boundaryChildren[boundaryResponse?.code], + boundaryCodes, + boundaryChildren + ); + request.body.boundariesCombined = 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 header = { - ...defaultheader, - cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, - } - const boundaryResponse = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, request.body, params, undefined, undefined, header); - 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."); - } + // var { boundaries } = CampaignDetails; + var boundaries = await getBoundariesFromCampaignSearchResponse( + request, + CampaignDetails + ); + const rootBoundary = getRootBoundaryCode(boundaries); + if (rootBoundary) { + const params = { + tenantId: request?.body?.ResourceDetails?.tenantId, + codes: rootBoundary, + hierarchyType: request?.body?.ResourceDetails?.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, + request.body, + params, + undefined, + undefined, + header + ); + 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); +function reorderBoundariesWithParentFirst( + boundaries: any[], + boundaryProjectMapping: any +) { + const startTime = Date.now(); + + const boundaryGraph = new Map(); + const inDegree = new Map(); + + logger.info(`Started processing ${boundaries.length} boundaries...`); + + // Step 1: Build the graph and calculate in-degrees + boundaries.forEach((boundary) => { + const code = boundary.code; + boundaryGraph.set(code, []); + inDegree.set(code, 0); // Initialize in-degree for each boundary + }); + + boundaries.forEach((boundary) => { + const code = boundary.code; + const parentCode = boundaryProjectMapping[code]?.parent; + + if (parentCode) { + boundaryGraph.get(parentCode).push(code); // Parent points to child + inDegree.set(code, inDegree.get(code) + 1); // Increment in-degree of child + } + }); + + const graphConstructionTime = Date.now(); + logger.info( + `Graph construction completed. Time taken: ${( + (graphConstructionTime - startTime) / 1000 + ).toFixed(2)} seconds.` + ); + + // Step 2: Perform topological sort using Kahn's Algorithm + const queue: any = []; + const sortedBoundaries = []; + + // Enqueue nodes with 0 in-degree + boundaries.forEach((boundary) => { + if (inDegree.get(boundary.code) === 0) { + queue.push(boundary); + } + }); + + let nodesProcessed = 0; + while (queue.length > 0) { + const currentBoundary = queue.shift(); + sortedBoundaries.push(currentBoundary); + nodesProcessed++; + + // Log progress periodically + if (nodesProcessed % 500 === 0) { + const elapsed = (Date.now() - startTime) / 1000; + const avgTimePerBoundary = elapsed / nodesProcessed; + const estimatedRemaining = avgTimePerBoundary * (boundaries.length - nodesProcessed); + logger.info( + `Processed ${nodesProcessed} boundaries. Elapsed: ${elapsed.toFixed( + 2 + )} seconds. Estimated time remaining: ${estimatedRemaining.toFixed(2)} seconds.` + ); + } + + const children = boundaryGraph.get(currentBoundary.code) || []; + children.forEach((childCode: any) => { + inDegree.set(childCode, inDegree.get(childCode) - 1); + if (inDegree.get(childCode) === 0) { + queue.push( + boundaries.find((boundary) => boundary.code === childCode) + ); + } + }); + } - if (parentIndex !== -1 && boundaryIndex !== -1 && parentIndex > boundaryIndex) { - reorderedBoundaries.splice(parentIndex + 1, 0, reorderedBoundaries.splice(boundaryIndex, 1)[0]); - break; - } - } - } - } + // Check for cycles (remaining nodes with non-zero in-degree) + if (sortedBoundaries.length !== boundaries.length) { + throw new Error( + "Cycle detected in the boundary-parent relationships. Reordering failed." + ); + } + + const endTime = Date.now(); + logger.info( + `Reordering completed. Processed ${boundaries.length} boundaries in ${( + (endTime - startTime) / 1000 + ).toFixed(2)} seconds.` + ); + + return sortedBoundaries; } -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 reorderBoundariesOfDataAndValidate( + request: any, + localizationMap?: any +) { + if (request?.body?.ResourceDetails?.campaignId) { + // const searchBody = { + // RequestInfo: request?.body?.RequestInfo, + const CampaignDetails = { + ids: [request?.body?.ResourceDetails?.campaignId], + tenantId: request?.body?.ResourceDetails?.tenantId, + } + // }; + // const req: any = replicateRequest(request, searchBody); + const response = await searchProjectTypeCampaignService(CampaignDetails); + 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 header = { - ...defaultheader, - cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, - } - const boundaryResponse = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, request.body, params, undefined, undefined, header); - 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)); + // var { boundaries } = request?.body?.CampaignDetails; + var boundaries = request?.body?.boundariesCombined; + 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 header = { + ...defaultheader, + cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId + }${params.codes || ""}${params?.includeChildren || ""}`, + }; + const boundaryResponse = await httpRequest( + config.host.boundaryHost + config.paths.boundaryRelationship, + request.body, + params, + undefined, + undefined, + header + ); + if (boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]) { + const codesTargetMapping = await getCodesTarget(request, localizationMap); + if (codesTargetMapping) { + 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?.boundariesCombined) + ); + const start = Date.now(); + const sortedBoundaries = reorderBoundariesWithParentFirst( + request?.body?.boundariesCombined, + request?.body?.boundaryProjectMapping + ); + request.body.boundariesCombined = sortedBoundaries; + const end = Date.now(); + logger.info(`Execution time: ${(end - start) / 1000} seconds`); + logger.info("Reordered the Boundaries for mapping"); + logger.debug( + "Reordered Boundaries " + + getFormattedStringForDebug(request?.body?.boundariesCombined) + ); + return request.body.boundariesCombined; } 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) - } + 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; + } + 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 = { + const { projectId, tenantId } = request?.body?.CampaignDetails; + const projectSearchBody = { + RequestInfo: request?.body?.RequestInfo, + Projects: [ + { + id: projectId, tenantId: tenantId, - offset: 0, - limit: 1, - includeDescendants: true - } - logger.info("Project search params " + JSON.stringify(projectSearchParams)) - 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 [] - } + }, + ], + }; + const projectSearchParams = { + tenantId: tenantId, + offset: 0, + limit: 1, + includeDescendants: true, + }; + logger.info("Project search params " + JSON.stringify(projectSearchParams)); + 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, actionInUrl: any) { - const { startDate, endDate, projectId } = request?.body?.CampaignDetails - if ((startDate || endDate) && projectId && actionInUrl == "update") { - const projects = await getRelatedProjects(request); - 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") - } + const { startDate, endDate, projectId } = request?.body?.CampaignDetails; + if ((startDate || endDate) && projectId && actionInUrl == "update") { + const projects = await getRelatedProjects(request); + 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"); + let boundaryCodesWhoseTargetsHasToBeUpdated: any = []; + const { tenantId, resources } = request?.body?.CampaignDetails; + const boundaryWithTargetResource = resources?.filter( + (resource: any) => resource?.type == "boundaryWithTarget" + ); + if (boundaryWithTargetResource && boundaryWithTargetResource.length > 0) { + 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"); + throwError("FILE", 500, "DOWNLOAD_URL_NOT_FOUND"); } - const codeColumnName = getLocalizedName(createAndSearch?.boundaryWithTarget?.boundaryValidation?.column, localizationMap) - const targetData = await getTargetSheetDataAfterCode(fileResponse?.fileStoreIds?.[0]?.url, true, true, codeColumnName); + const codeColumnName = getLocalizedName( + createAndSearch?.boundaryWithTarget?.boundaryValidation?.column, + localizationMap + ); + const targetData = await getTargetSheetDataAfterCode( + request, + fileResponse?.fileStoreIds?.[0]?.url, + true, + true, + codeColumnName + ); const boundaryTargetMapping: any = {}; // 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']; - } - }); + // 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"]; + if ( + entry["Parent Target at the Selected Boundary level"] !== 0 && + entry["Parent Target at the Selected Boundary level"] !== + entry["Target at the Selected Boundary level"] + ) { + boundaryCodesWhoseTargetsHasToBeUpdated.push(entry[codeColumnName]); + } + } + }); } - logger.info("Boundary target mapping count" + Object.keys(boundaryTargetMapping)?.length); + logger.info( + "Boundary target mapping count" + + Object.keys(boundaryTargetMapping)?.length + ); + request.body.boundaryCodesWhoseTargetsHasToBeUpdated = + boundaryCodesWhoseTargetsHasToBeUpdated; return boundaryTargetMapping; + } else return null; } -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; +async function createProject( + request: any, + actionUrl: any, + localizationMap?: any +) { + await persistTrack( + request.body.CampaignDetails.id, + processTrackTypes.targetAndDeliveryRulesCreation, + processTrackStatuses.inprogress + ); + try { + logger.info("Create Projects started for the given Campaign"); + var { tenantId, projectType, projectId } = request?.body?.CampaignDetails; + var boundaries = request?.body?.boundariesCombined; 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 + 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, + }; + boundaries = await reorderBoundaries(request, localizationMap); + let boundariesAlreadyWithProjects: any; + if (request?.body?.parentCampaign) { + // make search to project with parent campaign root project id + const { projectId, tenantId } = request?.body?.parentCampaign; + const projectSearchResponse = + await fetchProjectsWithProjectId(request, projectId, tenantId); + boundariesAlreadyWithProjects = + getBoundaryProjectMappingFromParentCampaign( + request, + projectSearchResponse?.Project?.[0] + ); + } + + const boundaryCodesWhoseTargetsHasToBeUpdated = + request?.body?.boundaryCodesWhoseTargetsHasToBeUpdated; + if (boundaryCodesWhoseTargetsHasToBeUpdated) { + for (const boundary of boundaryCodesWhoseTargetsHasToBeUpdated) { + if ( + boundariesAlreadyWithProjects && + boundariesAlreadyWithProjects.size > 0 && + boundariesAlreadyWithProjects.has(boundary) + ) { + const projectSearchResponse = + await fetchProjectsWithBoundaryCodeAndReferenceId( + boundary, + tenantId, + request?.body?.CampaignDetails?.campaignNumber, + request?.body?.RequestInfo + ); + const projectToUpdate = projectSearchResponse?.Project?.[0]; + if (projectToUpdate) { + const filteredTargets = projectToUpdate.targets.filter( + (e: any) => + e.beneficiaryType == + request?.body?.CampaignDetails?.additionalDetails + ?.beneficiaryType + ); + if (filteredTargets.length == 0) { + projectToUpdate.targets = [ + { + beneficiaryType: + request?.body?.CampaignDetails?.additionalDetails + ?.beneficiaryType, + totalNo: + request?.body?.CampaignDetails?.codesTargetMapping[ + boundary + ], + targetNo: + request?.body?.CampaignDetails?.codesTargetMapping[ + boundary + ], + }, + ]; + } else { + const targetobj = filteredTargets[0]; + (targetobj.totalNo = + request?.body?.CampaignDetails?.codesTargetMapping[boundary]), + (targetobj.targetNo = + request?.body?.CampaignDetails?.codesTargetMapping[ + boundary + ]); + projectToUpdate.targets = [targetobj]; + } + const projectUpdateBody = { + RequestInfo: request?.body?.RequestInfo, + Projects: [projectToUpdate], + }; + + await projectUpdateForTargets( + projectUpdateBody, + request, + boundary + ); } - 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) + } } - } + } + delete request.body.boundaryCodesWhoseTargetsHasToBeUpdated; + for (const boundary of boundaries) { + const boundaryCode = boundary?.code; + // Only proceed if the boundary code is not already mapped to an existing project + if ( + !boundariesAlreadyWithProjects || + (boundariesAlreadyWithProjects.size > 0 && + !boundariesAlreadyWithProjects.has(boundaryCode)) + ) { + // Set the address for the project + Projects[0].address = { + tenantId: tenantId, + boundary: boundaryCode, + boundaryType: boundary?.type, + }; + + // Handle parent project assignment if present in boundaryProjectMapping + const parent = + request?.body?.boundaryProjectMapping?.[boundaryCode]?.parent; + const parentProjectId = + request?.body?.boundaryProjectMapping?.[parent]?.projectId; + + if (parent && parentProjectId) { + await confirmProjectParentCreation(request, parentProjectId); + Projects[0].parent = parentProjectId; + } else { + Projects[0].parent = null; + } + + // Set the reference ID and project targets + Projects[0].referenceID = request?.body?.CampaignDetails?.campaignNumber; + (Projects[0].targets = [ + { + beneficiaryType: + request?.body?.CampaignDetails?.additionalDetails + ?.beneficiaryType, + totalNo: + request?.body?.CampaignDetails?.codesTargetMapping[ + boundaryCode + ], + targetNo: + request?.body?.CampaignDetails?.codesTargetMapping[ + boundaryCode + ], + }, + ]); + 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 + ); } - 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 updateProjectDates(request, actionInUrl); - await enrichAndPersistProjectCampaignRequest(request, actionInUrl, false, localizationMap) - } - } catch (error: any) { - console.log(error) - logger.error(error) - enrichAndPersistCampaignWithError(request?.body, error) + 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 + ); + } else { + await updateProjectDates(request, actionInUrl); + await enrichAndPersistProjectCampaignRequest( + request, + actionInUrl, + false, + localizationMap + ); } + delete request.body?.boundariesCombined; + } catch (error: any) { + console.log(error); + logger.error(error); + await enrichAndPersistCampaignWithError(request?.body, error); + } } async function processBasedOnAction(request: any, actionInUrl: any) { - if (actionInUrl == "create") { - request.body.CampaignDetails.id = uuidv4() - } - await enrichAndPersistProjectCampaignForFirst(request, actionInUrl, true) - processAfterPersist(request, actionInUrl) + if (actionInUrl == "create") { + request.body.CampaignDetails.id = uuidv4(); + } + await enrichAndPersistProjectCampaignForFirst(request, actionInUrl, true); + if ( + actionInUrl == "create" && + request.body?.parentCampaign && + request?.body?.CampaignDetails?.action === "draft" + ) { + callGenerateWhenChildCampaigngetsCreated(request); + } + processAfterPersist(request, actionInUrl); } - async function getLocalizedHierarchy(request: any, localizationMap: any) { - var hierarchy = await getHierarchy(request, request?.query?.tenantId, request?.query?.hierarchyType); - var modifiedHierarchy = hierarchy.map((ele) => - `${request?.query?.hierarchyType}_${ele}`.toUpperCase() + var hierarchy = await getHierarchy( + request, + request?.query?.tenantId, + request?.query?.hierarchyType + ); + var modifiedHierarchy = hierarchy.map((ele) => + `${request?.query?.hierarchyType}_${ele}`.toUpperCase() + ); + var resultHierarchy = getLocalizedHeaders(modifiedHierarchy, localizationMap); + return resultHierarchy; +} + +async function appendSheetsToWorkbook( + request: any, + boundaryData: any[], + differentTabsBasedOnLevel: any, + localizationMap?: any, + fileUrl?: any +) { + try { + logger.info( + "Received Boundary data for generating different tabs based on configured boundary level" ); - var resultHierarchy = getLocalizedHeaders( - modifiedHierarchy, - localizationMap + const hierarchy: any[] = await getLocalizedHierarchy( + request, + localizationMap ); - return resultHierarchy; -} - - -async function appendSheetsToWorkbook(request: any, boundaryData: any[], differentTabsBasedOnLevel: any, localizationMap?: any) { - try { - logger.info("Received Boundary data for generating different tabs based on configured boundary level"); - const hierarchy: any[] = await getLocalizedHierarchy(request, localizationMap); - const workbook = getNewExcelWorkbook(); - const type = request?.query?.type; - const headingInSheet = headingMapping?.[type]; - 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); - logger.info("appending different districts tab in the sheet started") - await appendDistricts(request, workbook, uniqueDistrictsForMainSheet, differentTabsBasedOnLevel, boundaryData, localizationMap, districtLevelRowBoundaryCodeMap, hierarchy); - logger.info("Sheet with different tabs generated successfully"); - return workbook; - } catch (error) { - console.log(error); - throw Error("An error occurred while creating tabs based on district:"); - } -} - - -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); - for (const uniqueData of uniqueDistrictsForMainSheet) { - const uniqueDataFromLevelForDifferentTabs = uniqueData.slice(uniqueData.lastIndexOf('#') + 1); - logger.info(`generating the boundary data for ${uniqueDataFromLevelForDifferentTabs} - ${differentTabsBasedOnLevel}`) - const districtDataFiltered = boundaryData.filter((boundary: any) => boundary[differentTabsBasedOnLevel] === uniqueDataFromLevelForDifferentTabs && boundary[hierarchy[hierarchy.length - 1]]); - const modifiedFilteredData = modifyFilteredData(districtDataFiltered, districtLevelRowBoundaryCodeMap.get(uniqueData), localizationMap); - if (modifiedFilteredData?.[0]) { - const newSheetData = [configurableColumnHeadersFromSchemaForTargetSheet]; - for (const data of modifiedFilteredData) { - var rowData: any[] = []; - for (const header of configurableColumnHeadersFromSchemaForTargetSheet) { - rowData.push(data[header] || ''); - } - newSheetData.push(rowData); - } - await createNewSheet(request, workbook, newSheetData, uniqueData, localizationMap, districtLevelRowBoundaryCodeMap, configurableColumnHeadersFromSchemaForTargetSheet); - logger.info(`${uniqueDataFromLevelForDifferentTabs} - ${differentTabsBasedOnLevel} boundary data generation completed`) + const workbook = getNewExcelWorkbook(); + const type = request?.query?.type; + const headingInSheet = headingMapping?.[type]; + const localisedHeading = getLocalizedName(headingInSheet, localizationMap); + await createReadMeSheet( + request, + workbook, + localisedHeading, + localizationMap + ); + const [ + mainSheetData, + uniqueDistrictsForMainSheet, + districtLevelRowBoundaryCodeMap, + ] = createBoundaryDataMainSheet( + request, + boundaryData, + differentTabsBasedOnLevel, + hierarchy, + localizationMap + ); + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + // const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); + 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( + request, + 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, + campaignObject, + fileUrl + ); + logger.info("Sheet with different tabs generated successfully"); + return workbook; + } catch (error) { + console.log(error); + throw Error("An error occurred while creating tabs based on district:"); + } +} + +async function appendDistricts( + request: any, + workbook: any, + uniqueDistrictsForMainSheet: any, + differentTabsBasedOnLevel: any, + boundaryData: any, + localizationMap: any, + districtLevelRowBoundaryCodeMap: any, + hierarchy: any, + campaignObject: any, + fileUrl?: any +) { + const configurableColumnHeadersFromSchemaForTargetSheet = + await getConfigurableColumnHeadersFromSchemaForTargetSheet( + request, + hierarchy, + boundaryData, + differentTabsBasedOnLevel, + campaignObject, + localizationMap + ); + let sheetNamesOfProcessedFile: any; + if (fileUrl) { + const processedWorkbook = await getTargetWorkbook(fileUrl, localizationMap); + sheetNamesOfProcessedFile = processedWorkbook.worksheets.map( + (sheet: any) => sheet.name + ); + } + for (const uniqueData of uniqueDistrictsForMainSheet) { + const uniqueDataFromLevelForDifferentTabs = uniqueData.slice( + uniqueData.lastIndexOf("#") + 1 + ); + logger.info( + `generating the boundary data for ${uniqueDataFromLevelForDifferentTabs} - ${differentTabsBasedOnLevel}` + ); + const districtDataFiltered = boundaryData.filter( + (boundary: any) => + boundary[differentTabsBasedOnLevel] === + uniqueDataFromLevelForDifferentTabs && + boundary[hierarchy[hierarchy.length - 1]] + ); + const modifiedFilteredData = modifyFilteredData( + districtDataFiltered, + districtLevelRowBoundaryCodeMap.get(uniqueData), + differentTabsBasedOnLevel, + localizationMap + ); + if (modifiedFilteredData?.[0]) { + const newSheetData = [configurableColumnHeadersFromSchemaForTargetSheet]; + for (const data of modifiedFilteredData) { + var rowData: any[] = []; + for (const header of configurableColumnHeadersFromSchemaForTargetSheet) { + rowData.push(data[header] || ""); } - } -} - - -async function createNewSheet(request: any, workbook: any, newSheetData: any, uniqueData: any, localizationMap: any, districtLevelRowBoundaryCodeMap: any, localizedHeaders: any) { - const newSheet = workbook.addWorksheet(getLocalizedName(districtLevelRowBoundaryCodeMap.get(uniqueData), localizationMap)); - addDataToSheet(newSheet, newSheetData, 'F3842D', 40); - const boundaryCodeColumnIndex = localizedHeaders.findIndex((header: any) => header === getLocalizedName(config?.boundary?.boundaryCode, localizationMap)); - const mdmsResponse = await getMdmsDataBasedOnCampaignType(request, localizationMap) - const columnsNotToBeFreezed = mdmsResponse?.columnsNotToBeFreezed; - const localizedColumnsNotToBeFreezed = getLocalizedHeaders(columnsNotToBeFreezed, localizationMap); - lockTargetFields(newSheet, localizedColumnsNotToBeFreezed, boundaryCodeColumnIndex); -} - - - - - -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); + newSheetData.push(rowData); + } + + await createNewSheet( + request, + workbook, + newSheetData, + uniqueData, + localizationMap, + districtLevelRowBoundaryCodeMap, + configurableColumnHeadersFromSchemaForTargetSheet, + campaignObject, + sheetNamesOfProcessedFile, + fileUrl + ); + 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, + campaignObject: any, + sheetNamesOfProcessedFile: any, + fileUrl?: any +) { + const newSheet = workbook.addWorksheet( + getLocalizedName( + districtLevelRowBoundaryCodeMap.get(uniqueData), + localizationMap + ) + ); + let modifiedNewSheetData: any = newSheetData; + const oldTargetColumnsToHide: any[] = []; + if (fileUrl) { + let processedDistrictSheetData: any; + if ( + sheetNamesOfProcessedFile.includes( + getLocalizedName( + districtLevelRowBoundaryCodeMap.get(uniqueData), + localizationMap + ) + ) + ) { + processedDistrictSheetData = await getSheetData( + fileUrl, + getLocalizedName( + districtLevelRowBoundaryCodeMap.get(uniqueData), + localizationMap + ), + false, + undefined, + localizationMap + ); + } + modifiedNewSheetData = modifyNewSheetData( + processedDistrictSheetData, + newSheetData, + localizedHeaders, + oldTargetColumnsToHide, + localizationMap + ); + } + addDataToSheet(request, newSheet, modifiedNewSheetData, "F3842D", 40); + if (oldTargetColumnsToHide && oldTargetColumnsToHide.length > 0) { + const columnIndexesToBeHidden: any[] = []; + oldTargetColumnsToHide.forEach((column: any) => { + const localizedColumn = getLocalizedName(column, localizationMap); + const columnIndex = getColumnIndexByHeader(newSheet, localizedColumn); + columnIndexesToBeHidden.push(columnIndex); }); - // Step 4: Return the modified filtered data - return modifiedFilteredData; -} - -async function generateFilteredBoundaryData(request: any, FiltersFromCampaignId: any) { - const rootBoundary: any = (FiltersFromCampaignId?.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, FiltersFromCampaignId?.Filters) - logger.info(`filtered the boundaries based on given criteria`) - return filteredBoundaryList; + hideColumnsOfProcessedFile(newSheet, columnIndexesToBeHidden); + } + let columnsNotToBeFreezed: any; + const boundaryCodeColumnIndex = localizedHeaders.findIndex( + (header: any) => + header === + getLocalizedName(config?.boundary?.boundaryCode, localizationMap) + ); + 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 + ); +} + +function modifyFilteredData( + districtDataFiltered: any, + targetBoundaryCode: any, + differentTabsBasedOnLevel: any, + localizationMap?: any +): any { + // Retrieve the localized version of the target boundary code if a localization map is provided + const desiredBoundaryCode = getLocalizedName( + targetBoundaryCode, + localizationMap + ); + // Filter the district data to include only rows where the boundary code matches the desired one + const modifiedFilteredData = districtDataFiltered.filter((row: any) => { + return row[differentTabsBasedOnLevel] == desiredBoundaryCode; + }); + // Return the filtered data + return modifiedFilteredData; +} + +async function generateFilteredBoundaryData( + request: any, + FiltersFromCampaignId: any +) { + const rootBoundary: any = (FiltersFromCampaignId?.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, + FiltersFromCampaignId?.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) - }; - } + 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 + ); - 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; + 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; + // 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); - } - } + 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); - } +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) { - console.log(error) - 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: any = await createExcelSheet(data, localizedHeaders); - const workbook = getNewExcelWorkbook(); - const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); - addDataToSheet(boundarySheet, boundarySheetData); - const boundaryFileDetails: any = await createAndUploadFile(workbook, 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; +async function boundaryGeometryManagement(request: any, localizationMap: any) { + try { + logger.info("Boundary Relationship Creation Starts For Geometry Data"); + await autoGenerateBoundaryCodesForGeoJson(request, localizationMap); + } catch (error: any) { + console.log(error); + await handleResouceDetailsError(request, error); + } } -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]; - } - } - +async function boundaryBulkUpload(request: any, localizationMap?: any) { + try { + logger.info("Boundary Relationship Creation Starts"); + await autoGenerateBoundaryCodes(request, localizationMap); + await generateProcessedFileAndPersist(request); + } catch (error: any) { + console.log(error); + await handleResouceDetailsError(request, error); + } +} + +function updateBoundaryDataForBoundaryManagement( + request: any, + boundaryData: any[], + localizationMap: any +): { updatedData: any[]; latLongData: [number, number][] } { + const latLongData: [number, number][] = []; + const latKey = getLocalizedName("HCM_ADMIN_CONSOLE_LAT", localizationMap); + const longKey = getLocalizedName("HCM_ADMIN_CONSOLE_LONG", localizationMap); + + boundaryData.forEach((row) => { + // Check if the row contains both latitude and longitude keys + if (latKey in row && longKey in row) { + // Push latitude and longitude to the latLongData array + latLongData.push([row[latKey], row[longKey]]); + + // Remove the latitude and longitude from the original row + delete row[latKey]; + delete row[longKey]; + } + }); + + // Return both the updated boundary data and latLongData + return { + updatedData: boundaryData, + latLongData, + }; +} + +async function autoGenerateBoundaryCodesForGeoJson( + request: any, + localizationMap?: any +) { + const { hierarchyType, tenantId } = request?.body?.ResourceDetails || {}; + // const type = request?.body?.ResourceDetails?.type; + const fileResponse = await httpRequest( + config.host.filestore + config.paths.filestore + "/url", + {}, + { tenantId, fileStoreIds: request?.body?.ResourceDetails?.fileStoreId }, + "get" + ); + var boundaryData = await getDataFromGeoJson( + fileResponse?.fileStoreIds?.[0]?.url + ); + const hierarchy = + (await getHierarchy(request, tenantId, hierarchyType)) || []; + const dataFromGeoJson = getGeoJsonData(boundaryData, hierarchy); + const childParentMap = getChildParentMap(dataFromGeoJson); + const countMap = new Map<{ key: string; value: string }, number>(); + const mappingMap = new Map<{ key: string; value: string }, string>(); + const boundaryMap = await getAutoGeneratedBoundaryCodesHandler( + dataFromGeoJson, + 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 boundaryGeoJsonAfterProcessing = addBoundaryCodeToGeoJsonData( + boundaryData, + hierarchy, + boundaryMap + ); + logger.info( + "Initiated the localisation message creation for the uploaded boundary" + ); + transformAndCreateLocalisation(boundaryMap, request); + const boundaryFileDetails: any = await createAndUploadJsonFile( + boundaryGeoJsonAfterProcessing, + request + ); + await updateAndPersistResourceDetails( + request, + boundaryFileDetails, + boundaryData?.name + ); + logger.info("Boundary Relationship Creation Completed"); +} + +async function updateAndPersistResourceDetails( + request: any, + boundaryFileDetails: any, + name: any +) { + const fileStoreId = boundaryFileDetails[0]?.fileStoreId; + const getLatestResourceDetails = await getResourceDetails(request); - return updatedObj; + if (getLatestResourceDetails == null) { + request.body.ResourceDetails = { + ...request?.body?.ResourceDetails, + processedFileStoreId: fileStoreId, + 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, + source: + request?.body?.ResourceDetails?.additionalDetails?.source == + "microplan" + ? "microplan" + : null, + [name]: [fileStoreId], + }, + }; + } else { + request.body.ResourceDetails = { + ...getLatestResourceDetails, + processedFileStoreId: fileStoreId, + status: + getLatestResourceDetails.status != resourceDataStatuses.invalid + ? resourceDataStatuses.completed + : resourceDataStatuses.invalid, + auditDetails: { + ...getLatestResourceDetails.auditDetails, + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now(), + }, + additionalDetails: + { + ...getLatestResourceDetails.additionalDetails, + sheetErrors: request?.body?.additionalDetailsErrors, + source: + getLatestResourceDetails.additionalDetails?.source == "microplan" + ? "microplan" + : null, + }, + }; + let additionalDetails = request?.body?.ResourceDetails?.additionalDetails; + if (additionalDetails && additionalDetails[name]) { + additionalDetails[name].push(fileStoreId); + } else { + additionalDetails = { ...additionalDetails, [name]: [fileStoreId] }; + } + request.body.ResourceDetails.additionalDetails = additionalDetails; + } + + const persistMessage: any = { ResourceDetails: request.body.ResourceDetails }; + await produceModifiedMessages( + persistMessage, + config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC + ); + logger.info( + `ResourceDetails to persist : ${request.body.ResourceDetails.type}` + ); +} + +async function getResourceDetails(request: any) { + const { tenantId, type, hierarchyType } = + request?.body?.ResourceDetails || request?.query; + const resourceDetails = request?.body?.ResourceDetails; + + request.body.SearchCriteria = request.body.SearchCriteria || {}; + + request.body.SearchCriteria = { + tenantId: tenantId, + type: type, + hierarchyType: hierarchyType, + status: resourceDataStatuses.completed, + }; + + const response = await searchDataService(request); + request.body.ResourceDetails = resourceDetails; + if (response.length > 0) { + response.sort( + (a: any, b: any) => + b.auditDetails.lastModifiedTime - a.auditDetails.lastModifiedTime + ); + return response[0]; + } else { + return null; + } +} +const addBoundaryCodeToGeoJsonData = ( + boundaryData: any, + hiearchy: any, + boundaryMap: Map +) => { + // const objectMap = boundaryMap.forEach((value, key) => {return { key: key.value, value: value }); + // Create the updatedBoundaryMap using a Map + const updatedBoundaryMap = new Map(); + boundaryMap.forEach((value, key) => { + const newKey = key.key + "_" + key.value; // Concatenate key and value + updatedBoundaryMap.set(newKey, value); // Set in the updated map + }); + + // Iterate through the boundary data + boundaryData.features.forEach((feature: any) => { + // Extract the properties object from the feature + const properties = feature.properties; + + // Iterate through the hierarchy + hiearchy.forEach((h: string) => { + // Build the field name + const field = h.toLowerCase() + "_name"; + + // Check if the field exists in the properties object + if (properties[field]) { + const boundaryName = h + "_" + properties[field]; + // Assign the boundary code to the properties object + properties[config.boundary.boundaryCode] = + updatedBoundaryMap.get(boundaryName); // Use .get() to access the Map + } }); - return updatedData; -} + }); -function modifyChildParentMap(childParentMap: Map, boundaryMap: Map): Map { - const modifiedMap: Map = new Map(); + return boundaryData; +}; +const getGeoJsonData = (boundaryData: any, hiearchy: any) => { + var data: any = []; + boundaryData.features?.forEach((feature: any) => { + const properties = feature.properties; + var row: any = []; + hiearchy.forEach((h: string) => { + const field = h.toLowerCase() + "_name"; + if (properties[field]) { + const d = { + key: h, + value: properties[field], + }; + row.push(d); + } + }); + data.push(row); + }); + return data; +}; - // 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; +const getDataFromGeoJson = async (url: string) => { + // Define headers for HTTP request + const headers = { + "Content-Type": "application/json", + Accept: "application/json", + }; + logger.info("loading for the file based on fileurl"); + // Make HTTP request to retrieve Excel file as arraybuffer + const responseFile = await httpRequest(url, null, {}, "get", "json", headers); + logger.info("received the file response"); + return responseFile; +}; - // Set the modified key-value pair in modifiedMap - modifiedMap.set(modifiedKey, modifiedValue); +const autoGenerateBoundaryCodes = async ( + request: any, + localizationMap?: any +) => { + const { hierarchyType, tenantId } = request?.body?.ResourceDetails || {}; + const hierarchy = + (await getHierarchy(request, tenantId, hierarchyType)) || []; + const headersOfBoundarySheet = hierarchy.map( + (e) => `${hierarchyType.toUpperCase()}_${e.toUpperCase()}` + ); + const localizedHeadersOfBoundarySheet = getLocalizedHeaders( + headersOfBoundarySheet, + localizationMap + ); + const type = request?.body?.ResourceDetails?.type; + const fileResponse = await httpRequest( + config.host.filestore + config.paths.filestore + "/url", + {}, + { tenantId, fileStoreIds: request?.body?.ResourceDetails?.fileStoreId }, + "get" + ); + const localizedBoundaryTab = getLocalizedName( + getBoundaryTabName(), + localizationMap + ); + var boundaryData = await getSheetData( + fileResponse?.fileStoreIds?.[0]?.url, + localizedBoundaryTab, + false, + undefined, + localizationMap + ); + var latLongData: any; + if (type === "boundaryManagement") { + validateBoundarySheetDataInCreateFlow( + boundaryData, + localizedHeadersOfBoundarySheet + ); + const result = await updateBoundaryDataForBoundaryManagement( + request, + boundaryData, + localizationMap + ); + latLongData = result.latLongData; + boundaryData = result.updatedData; + } + const updatedBoundaryData = updateBoundaryData(boundaryData, hierarchy); + const modifiedBoundaryData = modifyBoundaryDataHeaders( + updatedBoundaryData, + hierarchy, + localizationMap + ); + const [withBoundaryCode, withoutBoundaryCode] = modifyBoundaryData( + modifiedBoundaryData, + localizationMap + ); + const { mappingMap, countMap } = + getCodeMappingsOfExistingBoundaryCodes(withBoundaryCode); + 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 + ); + logger.info( + "Initiated the localisation message creation for the uploaded boundary" + ); + await transformAndCreateLocalisation(boundaryMap, request); + const modifiedHierarchy = hierarchy.map((ele) => + `${hierarchyType}_${ele}`.toUpperCase() + ); + var headers = [...modifiedHierarchy, config?.boundary?.boundaryCode]; + const data = prepareDataForExcel( + boundaryDataForSheet, + hierarchy, + boundaryMap + ); + if (type === "boundaryManagement") { + headers = [ + ...headers, + getLocalizedName("HCM_ADMIN_CONSOLE_LAT", localizationMap), + getLocalizedName("HCM_ADMIN_CONSOLE_LONG", localizationMap), + ]; + data.forEach((row: any[], index: string | number) => { + if (latLongData.length > index) { + row.push(latLongData[index][0], latLongData[index][1]); + } }); + } + const localizedHeaders = getLocalizedHeaders(headers, localizationMap); + const boundarySheetData: any = await createExcelSheet(data, localizedHeaders); + const workbook = getNewExcelWorkbook(); + const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); + addDataToSheet(request, boundarySheet, boundarySheetData, "93C47D", 40, true); + const boundaryFileDetails: any = await createAndUploadFile(workbook, request); + request.body.ResourceDetails.processedFileStoreId = + boundaryFileDetails?.[0]?.fileStoreId; +}; - return modifiedMap; +function updateBoundaryData(boundaryData: any[], hierarchy: any[]): any[] { + const map: Map = new Map(); + const count: Map = new Map(); + + boundaryData.forEach((row) => { + const keys = Object.keys(row).filter((key) => hierarchy.includes(key)); + 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]; + } + } -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; + return updatedObj; + }); + return updatedData; } -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 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; } -function getLocalizedName(expectedName: string, localizationMap?: { [key: string]: string }) { - if (!localizationMap || !(expectedName in localizationMap)) { - return expectedName; - } - const localizedName = localizationMap[expectedName]; - return localizedName; +async function convertSheetToDifferentTabs( + request: any, + boundaryData: any, + differentTabsBasedOnLevel: any, + localizationMap?: any, + fileUrl?: any +) { + // create different tabs on the level of hierarchy we want to + const updatedWorkbook = await appendSheetsToWorkbook( + request, + boundaryData, + differentTabsBasedOnLevel, + localizationMap, + fileUrl + ); + // 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"); - } +async function getTargetBoundariesRelatedToCampaignId( + request: any, + localizationMap?: any +) { + let CampaignDetailsNew: any; + if (request?.body?.ResourceDetails?.campaignId) { + // const searchBody = { + // RequestInfo: request?.body?.RequestInfo, + const CampaignDetails = { + ids: [request?.body?.ResourceDetails?.campaignId], + tenantId: request?.body?.ResourceDetails?.tenantId, + } + // const req: any = replicateRequest(request, searchBody); + const response = await searchProjectTypeCampaignService(CampaignDetails); + if (response?.CampaignDetails?.[0]) { + CampaignDetailsNew = response?.CampaignDetails?.[0]; + await addBoundariesForData(request, CampaignDetailsNew); + } else { + throwError( + "CAMPAIGN", + 400, + "CAMPAIGN_NOT_FOUND", + "Campaign not found while Validating sheet boundaries" + ); } - return CampaignDetails?.boundaries; + } + return CampaignDetailsNew?.boundaries; } - -function getFiltersFromCampaignSearchResponse(responseFromCampaignSearch: any) { - const boundaries = responseFromCampaignSearch?.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 } } +async function getFiltersFromCampaignSearchResponse( + request: any, + responseFromCampaignSearch: any +) { + const boundaries = await getBoundariesFromCampaignSearchResponse( + request, + responseFromCampaignSearch?.CampaignDetails?.[0] + ); + const boundariesModified = boundaries?.map((ele: any) => ({ + ...ele, + boundaryType: ele?.type, + })); + if (!boundariesModified) { + logger.info(`no boundaries found so considering the complete hierarchy`); + return { Filters: null }; + } + logger.info(`boundaries found for filtering`); + return { Filters: { boundaries: boundariesModified } }; +} + +const getConfigurableColumnHeadersBasedOnCampaignType = async ( + request: any, + localizationMap?: any +) => { + try { + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + let campaignType = campaignObject?.projectType; + const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); + campaignType = isSourceMicroplan + ? `${config?.prefixForMicroplanCampaigns}-${campaignType}` + : campaignType; + const isUpdate = request?.body?.parentCampaignObject ? true : false; + const mdmsResponse = await callMdmsTypeSchema( + request, + request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, + isUpdate, + 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` + ); + throwError( + "COMMON", + 400, + "SCHEMA_ERROR", + `Campaign Type ${campaignType} has not any columns configured in schema` + ); + } + // Extract columns from the response + const columnsForGivenCampaignId = mdmsResponse?.columns; + + // Get localized headers based on the column names + const headerColumnsAfterHierarchy = getLocalizedHeaders( + columnsForGivenCampaignId, + localizationMap + ); + if ( + !headerColumnsAfterHierarchy.includes( + getLocalizedName(config.boundary.boundaryCode, localizationMap) + ) + ) { + logger.error( + `Column Headers of generated Boundary Template does not have ${getLocalizedName( + config.boundary.boundaryCode, + localizationMap + )} column` + ); + throwError( + "COMMON", + 400, + "VALIDATION_ERROR", + `Column Headers of generated Boundary Template does not have ${getLocalizedName( + config.boundary.boundaryCode, + localizationMap + )} column` + ); + } + return headerColumnsAfterHierarchy; + } catch (error: any) { + console.log(error); + throwError( + "FILE", + 400, + "FETCHING_COLUMN_ERROR", + "Error fetching column Headers From Schema (either boundary code column not found or given Campaign Type not found in schema) Check logs" + ); + } }; +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(differentTabsBasedOnLevel, localizationMap) + ); + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); + var expectedHeadersForTargetSheetUptoHierarchy: any; + if (isSourceMicroplan) { + expectedHeadersForTargetSheetUptoHierarchy = localizedHierarchy; + } else { + expectedHeadersForTargetSheetUptoHierarchy = + index !== -1 + ? localizedHierarchy.slice(index) + : throwError( + "COMMON", + 400, + "VALIDATION_ERROR", + `${differentTabsBasedOnLevel} level not present in the hierarchy` + ); + } + const columnFromSchemaOfTargetTemplate = await generateDynamicTargetHeaders( + request, + campaignObject, + localizationMap + ); + const localizedcolumnFromSchemaOfTargetTemplate = getLocalizedHeaders( + columnFromSchemaOfTargetTemplate, + localizationMap + ); + let updatedLocalizedcolumnFromSchemaOfTargetTemplate = + localizedcolumnFromSchemaOfTargetTemplate; + if (request?.body?.parentCampaignObject) { + updatedLocalizedcolumnFromSchemaOfTargetTemplate = + localizedcolumnFromSchemaOfTargetTemplate + .map((item: any) => `${item}(OLD)`) + .concat(localizedcolumnFromSchemaOfTargetTemplate); + } + const expectedHeadersForTargetSheet = [ + ...expectedHeadersForTargetSheetUptoHierarchy, + getLocalizedName(config?.boundary?.boundaryCode, localizationMap), + ...updatedLocalizedcolumnFromSchemaOfTargetTemplate, + ]; + return expectedHeadersForTargetSheet; +} + +async function getDifferentTabGeneratedBasedOnConfig( + request: any, + boundaryDataGeneratedBeforeDifferentTabSeparation: any, + localizationMap?: any, + fileUrl?: any +) { + var boundaryDataGeneratedAfterDifferentTabSeparation: any = + boundaryDataGeneratedBeforeDifferentTabSeparation; + const boundaryData = await getBoundaryDataAfterGeneration( + boundaryDataGeneratedBeforeDifferentTabSeparation, + request, + localizationMap + ); + let differentTabsBasedOnLevel = await getBoundaryOnWhichWeSplit( + request, + request?.query?.tenantId + ); + 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] + ); + if ( + isKeyOfThatTypePresent && + boundaryTypeOnWhichWeSplit.length >= + parseInt(config?.boundary?.numberOfBoundaryDataOnWhichWeSplit) + ) { + logger.info( + `sinces the conditions are matched boundaries are getting splitted into different tabs` + ); + boundaryDataGeneratedAfterDifferentTabSeparation = + await convertSheetToDifferentTabs( + request, + boundaryData, + differentTabsBasedOnLevel, + localizationMap, + fileUrl + ); + } + return boundaryDataGeneratedAfterDifferentTabSeparation; +} + +async function getBoundaryOnWhichWeSplit(request: any, tenantId: any) { + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const MdmsCriteria: any = { + tenantId: tenantId, + schemaCode: `${config.values.moduleName}.${config.masterNameForSplitBoundariesOn}`, + filters: { + hierarchy: responseFromCampaignSearch?.CampaignDetails?.[0].hierarchyType, + }, + }; + const mdmsResponse: any = await searchMDMSDataViaV2Api(MdmsCriteria); + if (!Array.isArray(mdmsResponse?.mdms) || mdmsResponse.mdms.length === 0) { + throwError("MDMS", 500, "MDMS_DATA_NOT_FOUND_ERROR", `${responseFromCampaignSearch?.CampaignDetails?.[0].hierarchyType} hierarchy not configured in mdms data + ${config.values.moduleName}.${config.masterNameForSplitBoundariesOn}`) + } + return mdmsResponse?.mdms?.[0]?.data?.splitBoundariesOn; +} + +function checkIfSourceIsMicroplan(objectWithAdditionalDetails: any): boolean { + return objectWithAdditionalDetails?.additionalDetails?.source === "microplan"; +} + +function createIdRequests(employees: any[]): any[] { + if (employees && Array.isArray(employees) && employees.length > 0) { + const { tenantId } = employees[0]; // Assuming all employees have the same tenantId + return Array.from({ length: employees.length }, () => ({ + tenantId: tenantId, + idName: config?.values?.idgen?.idNameForUserNameGeneration, + idFormat: config?.values?.idgen?.formatForUserName, + })); + } else { + return []; + } +} + +async function createUniqueUserNameViaIdGen(request: any) { + const idgenurl = config?.host?.idGenHost + config?.paths?.idGen; + try { + // Make HTTP request to ID generation service + const result = await httpRequest( + idgenurl, + request?.body, + undefined, + undefined, + undefined, + undefined + ); + // Return null if ID generation fails + return result; + } catch (error: any) { + // Log the error + logger.error(`Error during ID generation: ${error.message}`); + + // Throw a custom error + throwError( + "ID_GENERATION", + 500, + "ID_GENERATION_FAILED", + `Error occurred while generating ID: ${error.message}` + ); + } +} -const getConfigurableColumnHeadersBasedOnCampaignType = async (request: any, localizationMap?: any) => { - try { - const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const campaignType = responseFromCampaignSearch?.CampaignDetails[0]?.projectType; +async function processFetchMicroPlan(request: any) { + try { + logger.info("Waiting for 1 second for templates to get generated..."); + await new Promise((resolve) => setTimeout(resolve, 1000)); - 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`) - throwError("COMMON", 400, "SCHEMA_ERROR", `Campaign Type ${campaignType} has not any columns configured in schema`); - } - // Extract columns from the response - const columnsForGivenCampaignId = mdmsResponse?.columns; - - // Get localized headers based on the column names - const headerColumnsAfterHierarchy = getLocalizedHeaders(columnsForGivenCampaignId, localizationMap); - if (!headerColumnsAfterHierarchy.includes(getLocalizedName(config.boundary.boundaryCode, localizationMap))) { - logger.error(`Column Headers of generated Boundary Template does not have ${getLocalizedName(config.boundary.boundaryCode, localizationMap)} column`) - throwError("COMMON", 400, "VALIDATION_ERROR", `Column Headers of generated Boundary Template does not have ${getLocalizedName(config.boundary.boundaryCode, localizationMap)} column`) - } - return headerColumnsAfterHierarchy; - } catch (error: any) { - console.log(error) - throwError("FILE", 400, "FETCHING_COLUMN_ERROR", "Error fetching column Headers From Schema (either boundary code column not found or given Campaign Type not found in schema) Check logs") - } + logger.info("Started processing fetch microplan"); -} + const { tenantId } = request.body.MicroplanDetails; + const localizationMap = await getLocalizedMessagesHandler(request, tenantId); + const resources: any = request?.body?.CampaignDetails?.resources || []; + const filteredResources = resources.filter( + (obj: any) => obj?.filestoreId && obj?.resourceId + ); + logger.info(`Filtered resources with valid IDs: ${filteredResources?.length}`); + logger.debug(`Filtered resources: ${getFormattedStringForDebug(filteredResources)}`); -async function getFinalValidHeadersForTargetSheetAsPerCampaignType(request: any, hierarchy: 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 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 localizedcolumnFromSchemaOfTargetTemplate = getLocalizedHeaders(columnFromSchemaOfTargetTemplate, localizationMap) - const expectedHeadersForTargetSheet = [...expectedHeadersForTargetSheetUptoHierarchy, ...localizedcolumnFromSchemaOfTargetTemplate]; - return expectedHeadersForTargetSheet; -} + const fetchOperations: Promise[] = []; -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); - 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]); - if (isKeyOfThatTypePresent && boundaryTypeOnWhichWeSplit.length >= parseInt(config?.boundary?.numberOfBoundaryDataOnWhichWeSplit)) { - logger.info(`sinces the conditions are matched boundaries are getting splitted into different tabs`) - boundaryDataGeneratedAfterDifferentTabSeparation = await convertSheetToDifferentTabs(request, boundaryData, differentTabsBasedOnLevel, localizationMap); + // Add fetch operations conditionally + if (filteredResources.length === 0 || filteredResources.every((obj: any) => obj?.type !== "facility")) { + fetchOperations.push(fetchFacilityData(request, localizationMap)); + } + if (filteredResources.length === 0 || filteredResources.every((obj: any) => obj?.type !== "boundaryWithTarget")) { + fetchOperations.push(fetchTargetData(request, localizationMap)); + } + if (filteredResources.length === 0 || filteredResources.every((obj: any) => obj?.type !== "user")) { + fetchOperations.push(fetchUserData(request, localizationMap)); } - return boundaryDataGeneratedAfterDifferentTabSeparation; -} + // Run all fetch operations in parallel + await Promise.all(fetchOperations); + logger.info("Updating campaign object after successful fetch microplan..."); + await updateCampaignAfterSearch(request, "MICROPLAN_COMPLETED"); + logger.info("Completed processing fetch microplan"); + } catch (error: any) { + logger.error(`Error during microplan fetch: ${error.message}`); + await updateCampaignAfterSearch(request, "MICROPLAN_FETCH_FAILED"); + } +} +async function updateCampaignAfterSearch(request: any, source = "MICROPLAN_FETCHING") { + logger.info("search campaign with id ") + const { tenantId, campaignId } = request.body.MicroplanDetails; + const campaignDetails = { + tenantId: tenantId, + ids: [campaignId] + } + const searchedCampaignResponse = await searchProjectTypeCampaignService(campaignDetails) + const searchedCamapignObject = searchedCampaignResponse?.CampaignDetails; + if (Array.isArray(searchedCamapignObject) && searchedCamapignObject.length > 0) { + const newRequestBody = { + RequestInfo: request.body.RequestInfo, // Retain the original RequestInfo + CampaignDetails: searchedCamapignObject?.[0] // campaigndetails from search response + }; + const req: any = replicateRequest(request, newRequestBody) + logger.info("Updating the received campaign object, source & its key"); + if (!req.body.CampaignDetails.additionalDetails) { + req.body.CampaignDetails.additionalDetails = {}; + } + req.body.CampaignDetails.additionalDetails.activity = source; + (!req.body?.CampaignDetails?.additionalDetails?.["disease"]) && (req.body.CampaignDetails.additionalDetails["disease"] = "MALARIA"), + (!req.body?.CampaignDetails?.additionalDetails?.["beneficiaryType"]) && (req.body.CampaignDetails.additionalDetails["beneficiaryType"] = + "INDIVIDUAL"); + req.body.CampaignDetails.additionalDetails["key"] = 1; + logger.debug( + `updated object with new source , disease & beneficiarytype ${getFormattedStringForDebug(req.body.CampaignDetails)}` + ); + await updateProjectTypeCampaignService(req); + logger.info("Updated the received campaign object"); + } else { + throwError("CAMPAIGN", 500, "CAMPAIGN_SEARCH_ERROR", "Error in campaign search"); + } +} export { - generateProcessedFileAndPersist, - convertToTypeData, - getChildParentMap, - addBoundaryCodeToData, - prepareDataForExcel, - extractCodesFromBoundaryRelationshipResponse, - searchProjectCampaignResourcData, - processDataSearchRequest, - getCodeMappingsOfExistingBoundaryCodes, - processBasedOnAction, - appendSheetsToWorkbook, - generateFilteredBoundaryData, - generateHierarchy, - createBoundaryMap, - autoGenerateBoundaryCodes, - convertSheetToDifferentTabs, - getBoundaryDataAfterGeneration, - boundaryBulkUpload, - enrichAndPersistCampaignWithError, - getLocalizedName, - reorderBoundaries, - reorderBoundariesOfDataAndValidate, - getTargetBoundariesRelatedToCampaignId, - getFiltersFromCampaignSearchResponse, - getConfigurableColumnHeadersBasedOnCampaignType, - getFinalValidHeadersForTargetSheetAsPerCampaignType, - getDifferentTabGeneratedBasedOnConfig -} + generateProcessedFileAndPersist, + convertToTypeData, + getChildParentMap, + addBoundaryCodeToData, + prepareDataForExcel, + extractCodesFromBoundaryRelationshipResponse, + searchProjectCampaignResourcData, + processDataSearchRequest, + getCodeMappingsOfExistingBoundaryCodes, + processBasedOnAction, + appendSheetsToWorkbook, + generateFilteredBoundaryData, + generateHierarchy, + createBoundaryMap, + autoGenerateBoundaryCodes, + convertSheetToDifferentTabs, + getBoundaryDataAfterGeneration, + boundaryBulkUpload, + enrichAndPersistCampaignWithError, + getLocalizedName, + reorderBoundaries, + reorderBoundariesOfDataAndValidate, + getTargetBoundariesRelatedToCampaignId, + getFiltersFromCampaignSearchResponse, + getConfigurableColumnHeadersBasedOnCampaignType, + getFinalValidHeadersForTargetSheetAsPerCampaignType, + getDifferentTabGeneratedBasedOnConfig, + checkIfSourceIsMicroplan, + getBoundaryOnWhichWeSplit, + createIdRequests, + createUniqueUserNameViaIdGen, + getRootBoundaryCode, + boundaryGeometryManagement, + getResourceDetails, + enrichInnerCampaignDetails, + processFetchMicroPlan, + updateCampaignAfterSearch, + processBoundary, +}; diff --git a/health-services/project-factory/src/server/utils/excelUtils.ts b/health-services/project-factory/src/server/utils/excelUtils.ts index 8624ed7b977..f640b3ddcd8 100644 --- a/health-services/project-factory/src/server/utils/excelUtils.ts +++ b/health-services/project-factory/src/server/utils/excelUtils.ts @@ -3,6 +3,9 @@ import { changeFirstRowColumnColour, throwError } from "./genericUtils"; import { httpRequest } from "./request"; import { logger } from "./logger"; import config from "../config"; +import { freezeUnfreezeColumnsForProcessedFile, getColumnIndexByHeader, hideColumnsOfProcessedFile } from "./onGoingCampaignUpdateUtils"; +import { getLocalizedName } from "./campaignUtils"; +import createAndSearch from "../config/createAndSearch"; /** * Function to create a new Excel workbook using the ExcelJS library * @returns {ExcelJS.Workbook} - A new Excel workbook object @@ -15,7 +18,7 @@ const getNewExcelWorkbook = () => { // Function to retrieve workbook from Excel file URL and sheet name const getExcelWorkbookFromFileURL = async ( fileUrl: string, - sheetName: string + sheetName?: string ) => { // Define headers for HTTP request const headers = { @@ -34,20 +37,23 @@ const getExcelWorkbookFromFileURL = async ( ); logger.info("received the file response"); - // Create a new workbook instance + const workbook = getNewExcelWorkbook(); await workbook.xlsx.load(responseFile); logger.info("workbook created based on the fileresponse"); - // Check if the specified sheet exists in the workbook - const worksheet = workbook.getWorksheet(sheetName); - if (sheetName && !worksheet) { - throwError( - "FILE", - 400, - "INVALID_SHEETNAME", - `Sheet with name "${sheetName}" is not present in the file.` - ); + + if (sheetName) { + // Check if the specified sheet exists in the workbook + const worksheet = workbook.getWorksheet(sheetName); + if (!worksheet) { + throwError( + "FILE", + 400, + "INVALID_SHEETNAME", + `Sheet with name "${sheetName}" is not present in the file.` + ); + } } // Return the workbook @@ -55,7 +61,7 @@ const getExcelWorkbookFromFileURL = async ( }; function updateFontNameToRoboto(worksheet: ExcelJS.Worksheet) { - worksheet.eachRow({ includeEmpty: true }, (row) => { + worksheet?.eachRow({ includeEmpty: true }, (row) => { row.eachCell({ includeEmpty: true }, (cell) => { // Preserve existing font properties const existingFont = cell.font || {}; @@ -71,8 +77,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 @@ -96,7 +102,7 @@ function formatWorksheet(worksheet: any, datas: any, headerSet: any) { worksheet.getColumn(1).width = 130; logger.info(`Freezing the whole sheet ${worksheet.name}`); - worksheet.eachRow((row: any) => { + worksheet?.eachRow((row: any) => { row.eachCell((cell: any) => { cell.protection = { locked: true }; }); @@ -104,7 +110,7 @@ function formatWorksheet(worksheet: any, datas: any, headerSet: any) { worksheet.protect('passwordhere', { selectLockedCells: true }); } -function performUnfreezeCells(sheet: any) { +function performUnfreezeCells(sheet: any, localizationMap?: any, fileUrl?: any) { logger.info(`Unfreezing the sheet ${sheet.name}`); let lastFilledColumn = 1; @@ -128,7 +134,7 @@ function performUnfreezeCells(sheet: any) { function performFreezeWholeSheet(sheet: any) { logger.info(`Freezing the whole sheet ${sheet.name}`); - sheet.eachRow((row: any) => { + sheet?.eachRow((row: any) => { row.eachCell((cell: any) => { cell.protection = { locked: true }; }); @@ -136,59 +142,127 @@ 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( + request: any, + sheet: any, + sheetData: any, + firstRowColor: string = '93C47D', + columnWidth: number = 40, + frozeCells: boolean = false, + frozeWholeSheet: boolean = false, + localizationMap?: any, + fileUrl?: any, + schema?: any +) { 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 + const worksheetRow = sheet.addRow(row); 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(request, sheet, frozeCells, frozeWholeSheet, localizationMap, fileUrl, schema); +} - // Enable text wrapping - cell.alignment = { wrapText: true }; - // Optionally lock the cell - if (frozeCells) { - cell.protection = { locked: true }; - } +// 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); + }); +} - // 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 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 }; + + if (frozeCells) { + cell.protection = { locked: true }; + } + cell.alignment = { vertical: 'top', horizontal: 'left', wrapText: true }; +} + +// 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(request: any, sheet: any, frozeCells: boolean, frozeWholeSheet: boolean, localizationMap?: any, fileUrl?: any, schema?: any) { + const type = (request?.query?.type || request?.body?.ResourceDetails?.type); + const typeWithoutWith = type.includes('With') ? type.split('With')[0] : type; + const createAndSearchConfig = createAndSearch[typeWithoutWith]; + const columnIndexesToBeFreezed: any = []; + const columnIndexesToBeHidden: any = []; if (frozeCells) { - performUnfreezeCells(sheet); + performUnfreezeCells(sheet, localizationMap, fileUrl); } if (frozeWholeSheet) { performFreezeWholeSheet(sheet); } + let columnsToBeFreezed: any[] = []; + let columnsToHide: any[] = []; + if (fileUrl) { + columnsToHide = ["HCM_ADMIN_CONSOLE_BOUNDARY_CODE_OLD",...schema?.columnsToHide]; + columnsToHide.forEach((column: any) => { + const localizedColumn = getLocalizedName(column, localizationMap); + const columnIndex = getColumnIndexByHeader(sheet, localizedColumn); + columnIndexesToBeHidden.push(columnIndex); + }); + + columnsToBeFreezed = ["HCM_ADMIN_CONSOLE_BOUNDARY_CODE_OLD", ...schema?.columnsToBeFreezed] + columnsToBeFreezed.forEach((column: any) => { + const localizedColumn = getLocalizedName(column, localizationMap); + const columnIndex = getColumnIndexByHeader(sheet, localizedColumn); + columnIndexesToBeFreezed.push(columnIndex); + }); + const activeColumnWhichIsNotToBeFreezed = createAndSearchConfig?.activeColumnName; + const boundaryCodeMandatoryColumnWhichIsNotToBeFreezed = getLocalizedName(config?.boundary?.boundaryCodeMandatory, localizationMap); + const localizedActiveColumnWhichIsNotToBeFreezed = getLocalizedName(activeColumnWhichIsNotToBeFreezed, localizationMap); + const columnIndexOfActiveColumn = getColumnIndexByHeader(sheet, localizedActiveColumnWhichIsNotToBeFreezed); + const columnIndexOfBoundaryCodeMandatory = getColumnIndexByHeader(sheet, boundaryCodeMandatoryColumnWhichIsNotToBeFreezed); + freezeUnfreezeColumnsForProcessedFile(sheet, columnIndexesToBeFreezed, [columnIndexOfActiveColumn, columnIndexOfBoundaryCodeMandatory]); // Example columns to freeze and unfreeze + hideColumnsOfProcessedFile(sheet, columnIndexesToBeHidden); + } 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) => { + newSheet?.eachRow((row: any) => { row.eachCell((cell: any) => { cell.protection = { locked: true }; }); @@ -204,7 +278,7 @@ function lockTargetFields(newSheet: any, columnsNotToBeFreezed: any, boundaryCod const targetColumnNumber = headers.indexOf(header) + 1; // Excel columns are 1-based logger.info(`Header: ${header}, Target Column Index: ${targetColumnNumber}`); if (targetColumnNumber > -1) { - newSheet.eachRow((row: any, rowNumber: number) => { + newSheet?.eachRow((row: any, rowNumber: number) => { changeFirstRowColumnColour(newSheet, 'B6D7A8', targetColumnNumber); if (rowNumber === 1) return; @@ -231,4 +305,4 @@ function lockTargetFields(newSheet: any, columnsNotToBeFreezed: any, boundaryCod } -export { getNewExcelWorkbook, getExcelWorkbookFromFileURL, formatWorksheet, addDataToSheet, lockTargetFields, updateFontNameToRoboto }; +export { getNewExcelWorkbook, getExcelWorkbookFromFileURL, formatWorksheet, addDataToSheet, lockTargetFields, updateFontNameToRoboto, formatFirstRow, formatOtherRows, finalizeSheet }; 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..83a2ec08ce1 --- /dev/null +++ b/health-services/project-factory/src/server/utils/generateUtils.ts @@ -0,0 +1,104 @@ +import { getLocalizedMessagesHandler, processGenerate, replicateRequest, throwError } from "./genericUtils"; +import _ from 'lodash'; +import { getFormattedStringForDebug, 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); +} +function isCampaignTypeSame(request: any) { + const existingCampaignType = request?.body?.ExistingCampaignDetails?.projectType; + const currentCampaignType = request?.body?.CampaignDetails?.projectType; + return _.isEqual(existingCampaignType, currentCampaignType); +} + +async function callGenerateIfBoundariesOrCampaignTypeDiffer(request: any) { + try { + const ExistingCampaignDetails = request?.body?.ExistingCampaignDetails; + const boundaries = request?.body?.boundariesCombined + if (ExistingCampaignDetails) { + if (!areBoundariesSame(ExistingCampaignDetails?.boundaries, boundaries) || isSourceDifferent(request) || !isCampaignTypeSame(request)) { + logger.info("Boundaries or Campaign Type differ, generating new resources"); + // Apply 2-second timeout after the condition check + await new Promise(resolve => setTimeout(resolve, 2000)); + + const newRequestBody = { + RequestInfo: request?.body?.RequestInfo, + Filters: { + boundaries: boundaries + } + }; + + const { query } = request; + const params = { + tenantId: request?.body?.CampaignDetails?.tenantId, + forceUpdate: 'true', + hierarchyType: request?.body?.CampaignDetails?.hierarchyType, + campaignId: request?.body?.CampaignDetails?.id + }; + logger.info(`generating new resources for the campaignId: ${request?.body?.CampaignDetails?.id}`); + logger.debug(`boundaries of the generate request : ${getFormattedStringForDebug(boundaries)}`) + 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}`); + } +} + +function isSourceDifferent(request: any){ + const ExistingCampaignDetails = request?.body?.ExistingCampaignDetails; + const CampaignDetails = request?.body?.CampaignDetails; + + if(CampaignDetails.additionalDetails.source !== ExistingCampaignDetails.additionalDetails.source){ + return true; + } + return false; +} + +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 { callGenerateIfBoundariesOrCampaignTypeDiffer, 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..2380ecbd795 100644 --- a/health-services/project-factory/src/server/utils/genericUtils.ts +++ b/health-services/project-factory/src/server/utils/genericUtils.ts @@ -2,20 +2,23 @@ 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 { getBoundarySheetData, getSheetData, createAndUploadFile, createExcelSheet, getTargetSheetData, callMdmsData, callMdmsTypeSchema, getConfigurableColumnHeadersBasedOnCampaignTypeForBoundaryManagement } 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 { getBoundaryColumnName, getBoundaryTabName } from "./boundaryUtils"; -import { getBoundaryDataService } from "../service/dataManageService"; +import { getLocaleFromRequest, getLocaleFromRequestInfo, getLocalisationModuleName } from "./localisationUtils"; +import { getBoundaryColumnName, getBoundaryTabName, getLatLongMapForBoundaryCodes } from "./boundaryUtils"; +import { getBoundaryDataService, searchDataService } from "../service/dataManageService"; import { addDataToSheet, formatWorksheet, getNewExcelWorkbook, updateFontNameToRoboto } from "./excelUtils"; import createAndSearch from "../config/createAndSearch"; +import { generateDynamicTargetHeaders } from "./targetUtils"; +import { buildSearchCriteria, checkAndGiveIfParentCampaignAvailable, fetchFileUrls, getCreatedResourceIds, modifyProcessedSheetData } from "./onGoingCampaignUpdateUtils"; +import { getReadMeConfigForMicroplan, getRolesForMicroplan, getUserDataFromMicroplanSheet, isMicroplanRequest, modifyBoundaryIfSourceMicroplan } from "./microplanUtils"; const NodeCache = require("node-cache"); const updateGeneratedResourceTopic = config?.kafka?.KAFKA_UPDATE_GENERATED_RESOURCE_DETAILS_TOPIC; @@ -51,6 +54,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 +249,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); + } + 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); } - queryResult = await executeQuery(queryString, queryValues); + + 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 +329,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,40 +363,74 @@ 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 }; + let fileUrlResponse: any; + if (type != 'boundaryManagement' && request?.query?.campaignId != 'default' && type != 'boundaryGeometryManagement') { + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + logger.info(`checks for parent campaign for type: ${type}`) + await checkAndGiveIfParentCampaignAvailable(request, campaignObject); + } + if (request?.body?.parentCampaignObject) { + const resourcesOfParentCampaign = request?.body?.parentCampaignObject?.resources; + const createdResourceId = getCreatedResourceIds(resourcesOfParentCampaign, type); + logger.info(` found createdResourceId as ${createdResourceId} `); + const searchCriteria = buildSearchCriteria(request, createdResourceId, type); + const responseFromDataSearch = await searchDataService(replicateRequest(request, searchCriteria)); + + const processedFileStoreIdForUSerOrFacility = responseFromDataSearch?.[0]?.processedFilestoreId; + fileUrlResponse = await fetchFileUrls(request, processedFileStoreIdForUSerOrFacility); + + } 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 + var boundaryDataSheetGeneratedAfterDifferentTabSeparation = boundaryDataSheetGeneratedBeforeDifferentTabSeparation; logger.info("generating different tabs logic ") - const boundaryDataSheetGeneratedAfterDifferentTabSeparation = await getDifferentTabGeneratedBasedOnConfig(request, boundaryDataSheetGeneratedBeforeDifferentTabSeparation, localizationMap) + boundaryDataSheetGeneratedAfterDifferentTabSeparation = await getDifferentTabGeneratedBasedOnConfig(request, boundaryDataSheetGeneratedBeforeDifferentTabSeparation, localizationMap, fileUrlResponse?.fileStoreIds?.[0]?.url) logger.info(`Different tabs based on level configured generated, ${JSON.stringify(boundaryDataSheetGeneratedAfterDifferentTabSeparation)}`) 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 == 'boundaryManagement' || type === 'boundaryGeometryManagement') { + // get boundary data from boundary relationship search api + logger.info("Generating Boundary Data") + const boundaryDataSheetGeneratedBeforeDifferentTabSeparation = await getBoundaryDataService(request, false); + logger.info(`Boundary data generated successfully: ${JSON.stringify(boundaryDataSheetGeneratedBeforeDifferentTabSeparation)}`); + // get boundary sheet data after being generated + const finalResponse = await getFinalUpdatedResponse(boundaryDataSheetGeneratedBeforeDifferentTabSeparation, newEntryResponse, request); + const generatedResourceNew: any = { generatedResource: finalResponse } + // send to update topic + await produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); + request.body.generatedResource = finalResponse; + logger.info("generation completed for boundary management create flow") + } else if (type == "facilityWithBoundary" || type == 'userWithBoundary') { - await processGenerateRequest(request, localizationMap); + await processGenerateRequest(request, localizationMap, filteredBoundary, fileUrlResponse?.fileStoreIds?.[0]?.url); 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); + } + catch (error: any) { + console.log(error) + await handleGenerateError(newEntryResponse, generatedResource, error); } } @@ -420,13 +484,81 @@ function correctParentValues(campaignDetails: any) { return campaignDetails; } -async function createFacilitySheet(request: any, allFacilities: any[], localizationMap?: { [key: string]: string }) { +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; + return dropdowns; +} + +function setHiddenColumns(request: any, schema: any, localizationMap?: { [key: string]: string }) { + // from schema.properties find the key whose value have value.hideColumn == true + const hiddenColumns = Object.entries(schema.properties).filter(([key, value]: any) => value.hideColumn == true).map(([key, value]: any) => getLocalizedName(key, localizationMap)); + logger.info(`Columns to hide ${JSON.stringify(hiddenColumns)}`); + request.body.hiddenColumns = hiddenColumns; +} + +async function getResourceDistributionStrategyTypes(request: any) { + const { RequestInfo = {} } = request?.body || {}; + const requestBody = { + RequestInfo, + MdmsCriteria: { + tenantId: request?.query?.tenantId, + schemaCode: "hcm-microplanning.ResourceDistributionStrategy" + } + }; + const url = config.host.mdmsV2 + config.paths.mdms_v2_search; + const response = await httpRequest(url, requestBody, undefined, undefined, undefined); + if (response?.mdms && Array.isArray(response?.mdms)) { + const resourceDistributionStrategyTypes = response?.mdms?.map((mdms: any) => mdms?.data?.resourceDistributionStrategyCode); + return resourceDistributionStrategyTypes; + } + else { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Error occured during resource distribution strategy type search"); + } +} + +async function getSchemaBasedOnSource(request: any, isSourceMicroplan: boolean, resourceDistributionStrategy: string) { const tenantId = request?.query?.tenantId; - const schema = await callMdmsTypeSchema(request, tenantId, "facility"); + let schema: any; + if (isSourceMicroplan) { + const resourceDistributionStrategyTypes = await getResourceDistributionStrategyTypes(request); + if (resourceDistributionStrategyTypes.includes(resourceDistributionStrategy)) { + schema = await callMdmsTypeSchema(request, tenantId, false, "facility", `MP-FACILITY-${resourceDistributionStrategy}`); + } + else { + throwError("CAMPAIGN", 500, "INVALID_RESOURCE_DISTRIBUTION_STRATEGY", `Invalid resource distribution strategy: ${resourceDistributionStrategy} ; Allowed resource distribution strategies: ${resourceDistributionStrategyTypes}`); + } + } else { + schema = await callMdmsTypeSchema(request, tenantId, false, "facility", "all"); + } + return schema; +} + +async function createFacilitySheet(request: any, allFacilities: any[], localizationMap?: { [key: string]: string }) { + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const isSourceMicroplan = checkIfSourceIsMicroplan(responseFromCampaignSearch?.CampaignDetails?.[0]); + request.body.isSourceMicroplan = isSourceMicroplan; + let schema: any = await getSchemaBasedOnSource(request, isSourceMicroplan, responseFromCampaignSearch?.CampaignDetails?.[0]?.additionalDetails?.resourceDistributionStrategy); const keys = schema?.columns; + setDropdownFromSchema(request, schema, localizationMap); + setHiddenColumns(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, @@ -467,17 +599,24 @@ function setAndFormatHeaders(worksheet: any, mainHeader: any, headerSet: any) { } async function createReadMeSheet(request: any, workbook: any, mainHeader: any, localizationMap = {}) { - const readMeConfig = await getReadMeConfig(request); + const isSourceMicroplan = await isMicroplanRequest(request); + let readMeConfig: any; + if (isSourceMicroplan) { + readMeConfig = await getReadMeConfigForMicroplan(request); + } + else { + readMeConfig = await getReadMeConfig(request); + } 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 +664,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) { @@ -577,7 +731,7 @@ function hideUniqueIdentifierColumn(sheet: any, column: any) { } -async function createFacilityAndBoundaryFile(facilitySheetData: any, boundarySheetData: any, request: any, localizationMap?: any) { +async function createFacilityAndBoundaryFile(facilitySheetData: any, boundarySheetData: any, request: any, localizationMap?: any, fileUrl?: any, schema?: any) { const workbook = getNewExcelWorkbook(); // Add facility sheet to the workbook @@ -591,29 +745,99 @@ async function createFacilityAndBoundaryFile(facilitySheetData: any, boundaryShe // Add facility sheet data const facilitySheet = workbook.addWorksheet(localizedFacilityTab); - addDataToSheet(facilitySheet, facilitySheetData, undefined, undefined, true); + addDataToSheet(request, facilitySheet, facilitySheetData, undefined, undefined, true, false, localizationMap, fileUrl, schema); hideUniqueIdentifierColumn(facilitySheet, createAndSearch?.["facility"]?.uniqueIdentifierColumn); changeFirstRowColumnColour(facilitySheet, 'E06666'); + let receivedDropdowns = request.body?.dropdowns; + logger.info("started adding dropdowns in facility", JSON.stringify(receivedDropdowns)) + + if (!receivedDropdowns || Object.keys(receivedDropdowns)?.length == 0) { + logger.info("No dropdowns found"); + receivedDropdowns = setDropdownFromSchema(request, schema, localizationMap); + logger.info("refetched drodowns", JSON.stringify(receivedDropdowns)) + } + await handledropdownthings(facilitySheet, receivedDropdowns); + await handleHiddenColumns(facilitySheet, request.body?.hiddenColumns); + // Add boundary sheet to the workbook const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap); const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); - addDataToSheet(boundarySheet, boundarySheetData, 'F3842D', 30, false, true); + boundarySheetData = modifyBoundaryIfSourceMicroplan(boundarySheetData, request); + addDataToSheet(request, boundarySheet, boundarySheetData, 'F3842D', 30, false, true); // Create and upload the fileData at row const fileDetails = await createAndUploadFile(workbook, request); request.body.fileDetails = fileDetails; } +async function handledropdownthings(sheet: any, dropdowns: any) { + let dropdownColumnIndex = -1; + if (dropdowns) { + logger.info("Dropdowns provided:", dropdowns); + for (const key of Object.keys(dropdowns)) { + if (dropdowns[key]) { + logger.info(`Processing dropdown key: ${key} with values: ${dropdowns[key]}`); + const firstRow = sheet.getRow(1); + firstRow.eachCell({ includeEmpty: true }, (cell: any, colNumber: any) => { + if (cell.value === key) { + dropdownColumnIndex = colNumber; + logger.info(`Found column index for dropdown "${key}": ${dropdownColumnIndex}`); + } + }); + + // If dropdown column index is found, set multi-select dropdown for subsequent rows + if (dropdownColumnIndex !== -1) { + logger.info(`Setting dropdown for column index: ${dropdownColumnIndex}`); + sheet.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, + error: 'Please select a value from the dropdown list.', + errorStyle: 'stop', + showErrorMessage: true, + errorTitle: 'Invalid Entry' + }; + } + }); + } else { + logger.info(`Dropdown column index not found for key: ${key}`); + } + } + } + } else { + logger.info("No dropdowns provided."); + } +} -// Helper function to add data to a sheet +async function handleHiddenColumns(sheet: any, hiddenColumns: any) { + // logger.info(sheet) + logger.info("hiddenColumns", hiddenColumns); + if (hiddenColumns) { + for (const columnName of hiddenColumns) { + const firstRow = sheet.getRow(1); + let colIndex = -1; + firstRow.eachCell({ includeEmpty: true }, (cell: any, colNumber: any) => { + if (cell.value === columnName) { + colIndex = colNumber; + } + if (colIndex !== -1) { + sheet.getColumn(colIndex).hidden = true + } + }); + } + } +} -async function createUserAndBoundaryFile(userSheetData: any, boundarySheetData: any, request: any, localizationMap?: { [key: string]: string }) { +async function createUserAndBoundaryFile(userSheetData: any, boundarySheetData: any, request: any, schema: any, localizationMap?: { [key: string]: string }, fileUrl?: any) { const workbook = getNewExcelWorkbook(); const localizedUserTab = getLocalizedName(config?.user?.userTab, localizationMap); const type = request?.query?.type; @@ -622,84 +846,259 @@ async function createUserAndBoundaryFile(userSheetData: any, boundarySheetData: await createReadMeSheet(request, workbook, localisedHeading, localizationMap); const userSheet = workbook.addWorksheet(localizedUserTab); - addDataToSheet(userSheet, userSheetData, undefined, undefined, true); + addDataToSheet(request, userSheet, userSheetData, undefined, undefined, true, false, localizationMap, fileUrl, schema); + hideUniqueIdentifierColumn(userSheet, createAndSearch?.["user"]?.uniqueIdentifierColumn); + + let receivedDropdowns = request.body?.dropdowns; + logger.info("started adding dropdowns in user", JSON.stringify(receivedDropdowns)) + + if (!receivedDropdowns || Object.keys(receivedDropdowns)?.length == 0) { + logger.info("No dropdowns found"); + receivedDropdowns = setDropdownFromSchema(request, schema, localizationMap); + logger.info("refetched drodowns", JSON.stringify(receivedDropdowns)) + } + await handledropdownthings(userSheet, receivedDropdowns); + await handleHiddenColumns(userSheet, request.body?.hiddenColumns); // Add boundary sheet to the workbook const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap) const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); - addDataToSheet(boundarySheet, boundarySheetData, 'F3842D', 30, false, true); + addDataToSheet(request, boundarySheet, boundarySheetData, 'F3842D', 30, false, true); const fileDetails = await createAndUploadFile(workbook, request) request.body.fileDetails = fileDetails; } -async function generateFacilityAndBoundarySheet(tenantId: string, request: any, localizationMap?: { [key: string]: string }) { +async function generateFacilityAndBoundarySheet(tenantId: string, request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any, fileUrl?: any) { + const type = request?.query?.type || request?.body?.ResourceDetails?.type; + const typeWithoutWith = type.includes('With') ? type.split('With')[0] : type; // 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); + let facilitySheetData: any; + const localizedFacilityTab = getLocalizedName(config?.facility?.facilityTab, localizationMap); + let schema: any; + if (fileUrl) { + /* fetch facility from processed file + and generate facility sheet data */ + schema = await callMdmsTypeSchema(request, tenantId, true, typeWithoutWith, "all"); + const processedFacilitySheetData = await getSheetData(fileUrl, localizedFacilityTab, false, undefined, localizationMap); + const modifiedProcessedFacilitySheetData = modifyProcessedSheetData(typeWithoutWith, processedFacilitySheetData, schema, localizationMap); + facilitySheetData = modifiedProcessedFacilitySheetData; + setDropdownFromSchema(request, schema, localizationMap); + } + else { + facilitySheetData = 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) { + logger.info("proceed with the filtered boundary data") + await createFacilityAndBoundaryFile(facilitySheetData, filteredBoundary, request, localizationMap, fileUrl, schema); + } + else { + const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); + await createFacilityAndBoundaryFile(facilitySheetData, boundarySheetData, request, localizationMap, fileUrl, schema); + } } -async function generateUserAndBoundarySheet(request: any, localizationMap?: { [key: string]: string }) { - const userData: any[] = []; + +async function generateUserSheet(request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any, userData?: any, fileUrl?: any) { const tenantId = request?.query?.tenantId; - const schema = await callMdmsTypeSchema(request, tenantId, "user"); + const type = request?.query?.type || request?.body?.ResourceDetails?.type; + const typeWithoutWith = type.includes('With') ? type.split('With')[0] : type; + let schema: any; + const isUpdate = fileUrl ? true : false; + schema = await callMdmsTypeSchema(request, tenantId, isUpdate, typeWithoutWith); + setDropdownFromSchema(request, schema, localizationMap); const headers = schema?.columns; const localizedHeaders = getLocalizedHeaders(headers, localizationMap); + const localizedUserTab = getLocalizedName(config?.user?.userTab, localizationMap); + let userSheetData: any; // 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 (fileUrl) { + /* fetch facility from processed file + and generate facility sheet data */ + const processedUserSheetData = await getSheetData(fileUrl, localizedUserTab, false, undefined, localizationMap); + const modifiedProcessedUserSheetData = modifyProcessedSheetData(typeWithoutWith, processedUserSheetData, schema, localizationMap); + userSheetData = modifiedProcessedUserSheetData; + } + else { + userSheetData = await createExcelSheet(userData, localizedHeaders); + } + if (filteredBoundary && filteredBoundary.length > 0) { + logger.info("proceed with the filtered boundary data") + await createUserAndBoundaryFile(userSheetData, filteredBoundary, request, schema, localizationMap, fileUrl); + } + else { + const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); + await createUserAndBoundaryFile(userSheetData, boundarySheetData, request, schema, localizationMap, fileUrl); + } +} + + +async function getCustomSheetData(request: any, type: any, sheetName: any) { + const { RequestInfo = {} } = request?.body || {}; + const requestBody = { + RequestInfo, + MdmsCriteria: { + tenantId: request?.query?.tenantId, + uniqueIdentifiers: [ + `${sheetName}.${type}` + ], + schemaCode: "HCM-ADMIN-CONSOLE.customSheetData" + } + }; + const url = config.host.mdmsV2 + config.paths.mdms_v2_search; + const header = { + ...defaultheader, + cachekey: `mdmsv2Seacrh${requestBody?.MdmsCriteria?.tenantId}${sheetName}${type}.${sheetName}${requestBody?.MdmsCriteria?.schemaCode}` + } + const response = await httpRequest(url, requestBody, undefined, undefined, undefined, header); + if (!response?.mdms?.[0]?.data) { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Error occured during customSheet config search"); + } + return response?.mdms?.[0]?.data; +} + +function getConvertedSheetData(allRows: any) { + const headersSet = new Set(); + allRows.forEach((row: any) => { + Object.keys(row).forEach(header => headersSet.add(header)); + }); + const headers: any = Array.from(headersSet); + + // Map rows to include all headers, filling missing values with "" + const sheetData = allRows.map((row: any) => + headers.map((header: any) => row[header] || "") + ); + + sheetData.unshift(headers); + return sheetData; +} +async function makeCustomSheetData(request: any, type: any, sheetName: any, workbook: any, localizationMap: any) { + const data = await getCustomSheetData(request, type, sheetName); + const sheetNameAfterTranslation = getLocalizedName(sheetName, localizationMap); + const customSheet = workbook.addWorksheet(sheetNameAfterTranslation); + const allRows: any = [] + for (const rows of data?.data) { + const rowData: any = {} + for (const row of rows) { + rowData[getLocalizedName(row?.column, localizationMap)] = getLocalizedName(row?.value, localizationMap); + } + allRows.push(rowData); + } + const sheetData = getConvertedSheetData(allRows); + addDataToSheet(request, customSheet, sheetData, undefined, undefined); + customSheet.protect('passwordhere', { + selectLockedCells: true, + selectUnlockedCells: true + }); +} + +async function generateUserSheetForMicroPlan( + request: any, + rolesForMicroplan: string[], + userData?: any, + localizationMap?: any, + fileUrl?: any +) { + const { tenantId, type } = request?.query; + const schema = await callMdmsTypeSchema(request, tenantId, false, "user", "microplan"); + setDropdownFromSchema(request, schema, localizationMap); + const headers = schema?.columns; + const localizedHeaders = getLocalizedHeaders(headers, localizationMap); + + logger.info("Generated an empty user template"); + + const workbook = getNewExcelWorkbook(); + const userSheetData = await createExcelSheet(userData, localizedHeaders); // Create data only once + + // Create and add ReadMe sheet + const headingInSheet = headingMapping?.[type]; + const localizedHeading = getLocalizedName(headingInSheet, localizationMap); + await createReadMeSheet(request, workbook, localizedHeading, localizationMap); + + + await makeCustomSheetData(request, request?.query?.type, "USER_MICROPLAN_SHEET_ROLES", workbook, localizationMap); + + // Loop through the rolesForMicroplan array to create sheets for each role + for (const role of rolesForMicroplan) { + // Create a sheet for each role, using the role name as the sheet name + const userSheet: any = workbook.addWorksheet(role); + addDataToSheet(request, userSheet, userSheetData, undefined, undefined, true, false, localizationMap, fileUrl, schema); + await handledropdownthings(userSheet, request.body?.dropdowns); + await handleHiddenColumns(userSheet, request.body?.hiddenColumns); + } + + // Create and upload the workbook file + const fileDetails = await createAndUploadFile(workbook, request); + request.body.fileDetails = fileDetails; +} + + + + +async function generateUserAndBoundarySheet(request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any, fileUrl?: any) { + const userData: any[] = []; + const tenantId = request?.query?.tenantId; + const isSourceMicroplan = await isMicroplanRequest(request); + if (isSourceMicroplan) { + const rolesForMicroplan = await getRolesForMicroplan(tenantId, localizationMap); + await generateUserSheetForMicroPlan(request, rolesForMicroplan, userData, localizationMap, fileUrl); + } + else { + await generateUserSheet(request, localizationMap, filteredBoundary, userData, fileUrl); + } } -async function processGenerateRequest(request: any, localizationMap?: { [key: string]: string }) { + +async function processGenerateRequest(request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any, fileUrl?: string) { const { type, tenantId } = request.query if (type == "facilityWithBoundary") { - await generateFacilityAndBoundarySheet(String(tenantId), request, localizationMap); + await generateFacilityAndBoundarySheet(String(tenantId), request, localizationMap, filteredBoundary, fileUrl); } if (type == "userWithBoundary") { - await generateUserAndBoundarySheet(request, localizationMap); + await generateUserAndBoundarySheet(request, localizationMap, filteredBoundary, fileUrl); } } -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); + logger.info("Generate flow :: processing new 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: { + ...item.additionalDetails, + error: { status: error.status, code: error.code, description: error.description, message: error.message - } || String(error) + } } }) 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 +1107,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 +1117,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 @@ -733,14 +1132,18 @@ async function enrichResourceDetails(request: any) { 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() } + 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) { @@ -819,9 +1222,7 @@ function modifyBoundaryData(boundaryData: any[], localizationMap?: any) { 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; +async function getDataFromSheetFromNormalCampaign(type: any, fileStoreId: any, tenantId: any, createAndSearchConfig: any, optionalSheetName?: any, localizationMap?: { [key: string]: string }) { 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"); @@ -830,17 +1231,35 @@ async function getDataFromSheet(request: any, fileStoreId: any, tenantId: any, c 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 getDataFromSheet(request: any, fileStoreId: any, tenantId: any, createAndSearchConfig: any, optionalSheetName?: any, localizationMap?: { [key: string]: string }) { + const isSourceMicroplan = request?.body?.ResourceDetails?.additionalDetails?.source == "microplan"; + const type = request?.body?.ResourceDetails?.type; + if (isSourceMicroplan) { + if (type == 'user') { + return await getUserDataFromMicroplanSheet(request, fileStoreId, tenantId, createAndSearchConfig, localizationMap); + } + else { + return await getDataFromSheetFromNormalCampaign(type, fileStoreId, tenantId, createAndSearchConfig, optionalSheetName, localizationMap); + } + } + else { + return await getDataFromSheetFromNormalCampaign(type, fileStoreId, tenantId, createAndSearchConfig, optionalSheetName, localizationMap); + } } async function getBoundaryRelationshipData(request: any, params: any) { - logger.info("Boundary relationship search initiated") + logger.info("Boundary relationship search initiated"); const url = `${config.host.boundaryHost}${config.paths.boundaryRelationship}`; const header = { ...defaultheader, - cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, + // cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, } const boundaryRelationshipResponse = await httpRequest(url, request.body, params, undefined, undefined, header); - logger.info("Boundary relationship search response received") + logger.info("Boundary relationship search response received"); return boundaryRelationshipResponse?.TenantBoundary?.[0]?.boundary; } @@ -855,13 +1274,15 @@ async function getDataSheetReady(boundaryData: any, request: any, localizationMa 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 modifiedReducedHierarchy = getLocalizedHeaders(reducedHierarchy.map(ele => `${request?.query?.hierarchyType}_${ele}`.toUpperCase()), localizationMap); // get Campaign Details from Campaign Search Api var configurableColumnHeadersBasedOnCampaignType: any[] = [] if (type == "boundary") { configurableColumnHeadersBasedOnCampaignType = await getConfigurableColumnHeadersBasedOnCampaignType(request, localizationMap); } - + if (type == "boundaryManagement" || type == "boundaryGeometryManagement") { + configurableColumnHeadersBasedOnCampaignType = await getConfigurableColumnHeadersBasedOnCampaignTypeForBoundaryManagement(request, localizationMap); + } const headers = (type !== "facilityWithBoundary" && type !== "userWithBoundary") ? [ ...modifiedReducedHierarchy, @@ -872,9 +1293,11 @@ async function getDataSheetReady(boundaryData: any, request: any, localizationMa getBoundaryColumnName() ]; const localizedHeaders = getLocalizedHeaders(headers, localizationMap); - const data = boundaryList.map(boundary => { + var boundaryCodeList: any[] = []; + var data = boundaryList.map(boundary => { const boundaryParts = boundary.split(','); const boundaryCode = boundaryParts[boundaryParts.length - 1]; + boundaryCodeList.push(boundaryCode); 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) => @@ -884,6 +1307,19 @@ async function getDataSheetReady(boundaryData: any, request: any, localizationMa mappedRowData[boundaryCodeIndex] = boundaryCode; return mappedRowData; }); + if (type == "boundaryManagement") { + logger.info("Processing data for boundaryManagement type") + const latLongBoundaryMap = await getLatLongMapForBoundaryCodes(request, boundaryCodeList); + for (let d of data) { + const boundaryCode = d[d.length - 1]; // Assume last element is the boundary code + + if (latLongBoundaryMap[boundaryCode]) { + const [latitude = null, longitude = null] = latLongBoundaryMap[boundaryCode]; // Destructure lat/long + d.push(latitude); // Append latitude + d.push(longitude); // Append longitude + } + } + } const sheetRowCount = data.length; if (type != "facilityWithBoundary") { request.body.generatedResourceCount = sheetRowCount; @@ -924,25 +1360,38 @@ function modifyDataBasedOnDifferentTab(boundaryData: any, differentTabsBasedOnLe } -async function getLocalizedMessagesHandler(request: any, tenantId: any, module = config.localisation.localizationModule) { +async function getLocalizedMessagesHandler(request: any, tenantId: any, module = config.localisation.localizationModule, overrideCache = false) { const localisationcontroller = Localisation.getInstance(); const locale = getLocaleFromRequest(request); + const localizationResponse = await localisationcontroller.getLocalisedData(module, locale, tenantId, overrideCache); + 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 }) { +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)) + }, {} as { [key: string]: any }), + + required: (schema?.required || []) + .map((key: string) => getLocalizedName(key, localizationMap)), + + unique: (schema?.unique || []) + .map((key: string) => getLocalizedName(key, localizationMap)) }; return translatedSchema; @@ -966,7 +1415,7 @@ 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('#'); @@ -983,25 +1432,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 mdmsResponse = await callMdmsTypeSchema(request, request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, request?.query?.type || request?.body?.ResourceDetails?.type, campaignType) + 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, false, 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 +1550,10 @@ export { changeFirstRowColumnColour, getConfigurableColumnHeadersFromSchemaForTargetSheet, createBoundaryDataMainSheet, - getMdmsDataBasedOnCampaignType + getMdmsDataBasedOnCampaignType, + shutdownGracefully, + appendProjectTypeToCapacity, + getLocalizedMessagesHandlerViaRequestInfo, + createFacilityAndBoundaryFile, + hideUniqueIdentifierColumn }; - - 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/logger/index.ts b/health-services/project-factory/src/server/utils/logger/index.ts index f2cad55890b..2e43c0011bf 100644 --- a/health-services/project-factory/src/server/utils/logger/index.ts +++ b/health-services/project-factory/src/server/utils/logger/index.ts @@ -25,8 +25,17 @@ 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" : ""); -} +export const getFormattedStringForDebug = (obj: any): string => { + try { + const convertedMessage = JSON.stringify(obj); + return convertedMessage.slice(0, DEFAULT_LOG_MESSAGE_COUNT) + + (convertedMessage.length > DEFAULT_LOG_MESSAGE_COUNT ? "\n ---more" : ""); + } catch (error : any ) { + if (error instanceof RangeError && error.message.includes("Invalid string length")) { + logger.error("The object is too big to convert into a string."); + } else { + logger.error(`An unexpected error occurred while formatting the object into a string : ${error?.message}`); + } + return "Error: Unable to format object for debug."; + } +}; diff --git a/health-services/project-factory/src/server/utils/microplanIntergration.ts b/health-services/project-factory/src/server/utils/microplanIntergration.ts new file mode 100644 index 00000000000..15f0d5713b8 --- /dev/null +++ b/health-services/project-factory/src/server/utils/microplanIntergration.ts @@ -0,0 +1,985 @@ +import { + callMdmsTypeSchema, + createAndUploadFile, + searchMDMS, +} from "../api/genericApis"; +import { getFormattedStringForDebug, logger } from "./logger"; + +import { + searchProjectTypeCampaignService, + updateProjectTypeCampaignService, +} from "../service/campaignManageService"; +import { + searchPlan, + searchPlanCensus, + searchPlanFacility, +} from "../api/microplanApis"; +import { + createAndPollForCompletion, + getTheGeneratedResource, +} from "./pollUtils"; +import { getExcelWorkbookFromFileURL } from "./excelUtils"; +import { + fetchFileFromFilestore, + searchBoundaryRelationshipData, + searchMDMSDataViaV1Api, +} from "../api/coreApis"; +import { getLocalizedName } from "./campaignUtils"; +import config from "../config"; +import { replicateRequest, throwError } from "./genericUtils"; +import { MDMSModels } from "../models"; +/** + * Adds data rows to the provided worksheet. + * @param worksheet The worksheet to which the data should be added. + * @param data Array of data rows to add. + */ +export async function addDataToWorksheet(worksheet: any, data: string[][]) { + data.forEach((row) => { + worksheet.addRow(row); + }); + + // Optionally, you can apply styles or adjust column widths + worksheet.columns.forEach((column: any) => { + column.width = 20; // Adjust column width to fit content + }); +} + +/** + * Updates existing rows in a worksheet with the given data, starting from row 2. + * @param worksheet The worksheet to update. + * @param data Array of data rows to insert. + */ +function updateWorksheetRows(worksheet: any, data: string[][]) { + data.forEach((rowData, index) => { + const rowNumber = 2 + index; // Start updating from row 2 + const row = worksheet.getRow(rowNumber); + + // Set values for each column in the row + rowData.forEach((cellValue, colIndex) => { + row.getCell(colIndex + 1).value = cellValue; // Column index starts at 1 + }); + + row.commit(); // Commit changes to the row + }); +} + +const getPlanFacilityMapByFacilityId = (planFacilityArray: any = []) => { + logger.info( + `filtered the plan facility response to have only facility which has only service boundarires` + ); + return planFacilityArray + ?.filter( + (planFacilityObj: any) => planFacilityObj?.serviceBoundaries?.length > 0 + ) + ?.reduce((acc: any, curr: any) => { + acc[curr?.facilityId] = curr; + return acc; + }, {}); +}; +const getRolesAndCount = (resources = [], userRoleMapping: any) => { + const USER_ROLE_MAP: any = {}; + + // Iterate through the userRoleMapping to determine rules for roles + userRoleMapping?.user?.forEach((mapping: any) => { + const { to, from, filter } = mapping; + + resources?.forEach((resource: any) => { + // Apply filter logic ensuring all criteria in `from` must match + const match = from.every((criteria: string) => + filter === "includes" + ? resource?.resourceType?.includes(criteria) + : resource?.resourceType === criteria + ); + + if (match) { + // Log the resource information + logger.info( + `filtered ${filter.toUpperCase()}: ${resource?.resourceType} :: ${ + resource?.estimatedNumber + }` + ); + + // Map roles based on the "to" field + USER_ROLE_MAP[to] = resource?.estimatedNumber; + } + }); + }); + + logger.info("Completed user role & boundary map"); + logger.info(`Map USER_ROLE_MAP ${getFormattedStringForDebug(USER_ROLE_MAP)}`); + + return { USER_ROLE_MAP }; +}; + +const getUserRoleMapWithBoundaryCode = ( + planFacilityArray: any = [], + userRoleMapping: any +) => { + return planFacilityArray?.reduce((acc: any, curr: any) => { + acc[curr?.locality] = { + // ...curr, + ...getRolesAndCount( + curr?.resources?.filter( + (resource: any) => resource?.estimatedNumber > 0 + ), + userRoleMapping + ), + }; + return acc; + }, {}); +}; + +function consolidateUserRoles( + userBoundaryMap: any, + boundaryiwthchildrednMap: any +) { + const result: any = {}; + + // Iterate through all parent boundaries + for (const parentBoundary in boundaryiwthchildrednMap) { + const children = boundaryiwthchildrednMap[parentBoundary]; + const consolidatedRoles: any = {}; + + // Process each child boundary + children.forEach((child: any) => { + const childCode = child.code; + const userRoles = userBoundaryMap[childCode]?.USER_ROLE_MAP || {}; + + // Aggregate roles for the parent boundary + for (const role in userRoles) { + if (!consolidatedRoles[role]) { + consolidatedRoles[role] = 0; + } + consolidatedRoles[role] += userRoles[role]; + } + }); + + // Attach consolidated roles to the parent boundary + result[parentBoundary] = { + parentBoundary, + children, + consolidatedRoles, + }; + } + + return result; +} + +// // Example Usage +// const consolidatedData = consolidateUserRoles(userBoundaryMap, boundaryiwthchildrednMap); +// console.log(JSON.stringify(consolidatedData, null, 2)); + +const getPlanCensusMapByBoundaryCode = (censusArray: any = []) => { + return censusArray?.reduce((acc: any, curr: any) => { + acc[curr?.boundaryCode] = curr; + return acc; + }, {}); +}; + +export const fetchFacilityData = async (request: any, localizationMap: any) => { + const { tenantId, planConfigurationId, campaignId } = + request.body.MicroplanDetails; + logger.info( + `doing the facility data fetch for planConfigurationId: ${planConfigurationId} and campaignId: ${campaignId} ` + ); + const facilityAdminSchema = await callMdmsTypeSchema( + request, + tenantId, + true, + "facility" + ); + const localizedHeadersMap = getLocalizedHeadersMapForFacility( + facilityAdminSchema.descriptionToFieldMap, + localizationMap + ); + const planFacilityResponse = await searchPlanFacility( + planConfigurationId, + tenantId + ); + logger.info(`got the facility mapping from the plan facility api`); + + const facilityBoundaryMap = + getPlanFacilityMapByFacilityId(planFacilityResponse); + logger.debug( + `created facilityBoundaryMap :${getFormattedStringForDebug( + facilityBoundaryMap + )}` + ); + + const generatedFacilityTemplateFileStoreId = await getTheGeneratedResource( + campaignId, + tenantId, + "facilityWithBoundary", + request.body.CampaignDetails?.hierarchyType + ); + logger.debug( + `downloadresponse fetchFacilityData ${getFormattedStringForDebug( + generatedFacilityTemplateFileStoreId + )}` + ); + const fileUrl = await fetchFileFromFilestore( + generatedFacilityTemplateFileStoreId, + tenantId + ); + logger.debug( + `downloadresponse fileUrl ${getFormattedStringForDebug(fileUrl)}` + ); + const workbook = await getExcelWorkbookFromFileURL( + fileUrl, + getLocalizedName(config?.facility?.facilityTab, localizationMap) + ); + logger.info(`workbook created for facility`); + + const updatedWorksheet = await findAndChangeFacilityData( + workbook.getWorksheet( + getLocalizedName(config?.facility?.facilityTab, localizationMap) + ), + facilityBoundaryMap, + localizedHeadersMap + ); + logger.info( + `workbook updated for facility with the data received from microplan` + ); + + const responseData = + updatedWorksheet && (await createAndUploadFile(workbook, request)); + logger.info( + "facility File updated successfully:" + JSON.stringify(responseData) + ); + if (responseData?.[0]?.fileStoreId) { + logger.info( + "facility File updated successfully:" + + JSON.stringify( + responseData?.[0]?.fileStoreId + " for campaignid : " + campaignId + ) + ); + } else { + throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); + } + + const polledResponseOfDataCreate = await validateSheet( + request, + tenantId, + "facility", + responseData?.[0]?.fileStoreId, + campaignId, + request.body.CampaignDetails.hierarchyType + ); + if ( + Array.isArray(polledResponseOfDataCreate) && + polledResponseOfDataCreate.length > 0 + ) { + await updateCampaignDetailsAfterSearch( + request, + polledResponseOfDataCreate?.[0], + "facility" + ); + logger.info( + `updated the resources of facility resource id ${polledResponseOfDataCreate?.[0]?.id}` + ); + } + logger.info( + `updated the resources of facility for campaignid : ${campaignId} and planid: ${planConfigurationId} ` + ); +}; + +function getLocalizedHeadersMapForFacility( + descriptionToFieldMap: Record, + localizationMap: any +) { + for (const [key, value] of Object.entries(descriptionToFieldMap)) { + descriptionToFieldMap[key] = getLocalizedName(value, localizationMap); + } + return descriptionToFieldMap; +} + +export const fetchTargetData = async (request: any, localizationMap: any) => { + const { tenantId, planConfigurationId, campaignId } = + request.body.MicroplanDetails; + logger.info( + `doing the target data fetch for planConfigurationId: ${planConfigurationId} and campaignId: ${campaignId} ` + ); + + const { projectType } = request.body.CampaignDetails; + const campaignType = "Target-" + projectType; + const userRoleMapping = await fetchUserRoleMappingFromMDMS(tenantId); + logger.info("received mdms data for target column mapping"); + logger.debug( + `target column mapping ${getFormattedStringForDebug(userRoleMapping)}` + ); + const planCensusResponse = await searchPlanCensus( + planConfigurationId, + tenantId, + getBoundariesFromCampaign(request.body.CampaignDetails)?.length + ); + logger.info(`got the target mapping from the census api`); + + const targetBoundaryMap = getPlanCensusMapByBoundaryCode(planCensusResponse); + logger.debug( + `created targetBoundaryMap :${getFormattedStringForDebug( + targetBoundaryMap + )}` + ); + + const generatedTargetTemplateFileStoreId = await getTheGeneratedResource( + campaignId, + tenantId, + "boundary", + request.body.CampaignDetails?.hierarchyType + ); + logger.debug( + `downloadresponse target ${getFormattedStringForDebug( + generatedTargetTemplateFileStoreId + )}` + ); + const fileUrl = await fetchFileFromFilestore( + generatedTargetTemplateFileStoreId, + tenantId + ); + logger.debug( + `downloadresponse target ${getFormattedStringForDebug(fileUrl)}` + ); + + const workbook = await getExcelWorkbookFromFileURL(fileUrl); + logger.info(`workbook created for target`); + + await workbook.worksheets.forEach(async (worksheet) => { + logger.info(`Processing worksheet: ${worksheet.name}`); + logger.info(`skipping processing worksheet: ${getLocalizedName(config?.boundary?.boundaryTab, localizationMap)} and ${getLocalizedName(config?.values?.readMeTab, localizationMap)} `); + + if ( + worksheet.name !== + getLocalizedName(config?.boundary?.boundaryTab, localizationMap) && + worksheet.name !== + getLocalizedName(config?.values?.readMeTab, localizationMap) + ) { + // harcoded to be changed + // Iterate over rows (skip the header row) + await findAndChangeTargetData( + worksheet, + targetBoundaryMap, + userRoleMapping[campaignType], + localizationMap + ); + } + }); + logger.info( + `workbook updated for target with the data received from microplan` + ); + + const responseData = await createAndUploadFile(workbook, request); + + logger.info( + "Target File updated successfully:" + JSON.stringify(responseData) + ); + if (responseData?.[0]?.fileStoreId) { + logger.info( + "Target File updated successfully:" + + JSON.stringify( + responseData?.[0]?.fileStoreId + " for campaignid : " + campaignId + ) + ); + } else { + throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); + } + const polledResponseOfDataCreate = await validateSheet( + request, + tenantId, + "boundaryWithTarget", + responseData?.[0]?.fileStoreId, + campaignId, + request.body.CampaignDetails.hierarchyType + ); + + if ( + Array.isArray(polledResponseOfDataCreate) && + polledResponseOfDataCreate.length > 0 + ) { + await updateCampaignDetailsAfterSearch( + request, + polledResponseOfDataCreate?.[0], + "boundaryWithTarget" + ); + logger.info( + `updated the resources of facility resource id ${polledResponseOfDataCreate?.[0]?.id}` + ); + } + logger.info( + `updated the resources of target for campaignid : ${campaignId} and planid: ${planConfigurationId} ` + ); +}; + +function findAndChangeUserData(worksheet: any, mappingData: any) { + logger.info( + `Received for facility mapping, enitity count : ${ + Object.keys(mappingData)?.length + }` + ); + logger.debug(`${getFormattedStringForDebug(mappingData)}, "mappingData user`); + // column no is // harcoded to be changed + const mappedData: any = {}; + + const dataRows: any = []; + Object.keys(mappingData).map((key) => { + const roles = Object.keys(mappingData[key].consolidatedRoles); + roles.map((role) => { + for (let i = 0; i < mappingData[key].consolidatedRoles?.[role]; i++) { + dataRows.push(["", "", role, "Permanent", key, "Active"]); + } + }); + }); + logger.debug( + `${getFormattedStringForDebug(dataRows)},"dataRows to be pushed` + ); + updateWorksheetRows(worksheet, dataRows); + + logger.info( + `Updated the boundary & active/inactive status information in facility received from the microplan` + ); + logger.info( + `mapping completed for facility enitity count : ${ + Object.keys(mappedData)?.length + }` + ); + logger.info( + `mapping not found for facility entity count : ${ + Object.keys(mappingData)?.length - Object.keys(mappedData)?.length + }` + ); + return worksheet; +} + +function findAndChangeFacilityData( + worksheet: any, + mappingData: Record< + string, + { + additionalDetails: any; + serviceBoundaries: string[]; + } + >, + headersMap: Record +) { + let facilityCodeIndex: number = 1; + let boundaryCodeIndex: number = 6; + let facilityUsageIndex: number = 7; + let headerValues: any = []; + + const mappedData: Record = {}; + const missingFacilities: string[] = []; + + // Iterate through each row in the worksheet + worksheet.eachRow((row: any, rowIndex: number) => { + if (rowIndex === 1) { + headerValues = row.values; + facilityCodeIndex = headerValues.indexOf("Facility Code"); + boundaryCodeIndex = headerValues.indexOf(headersMap["Boundary Code"]); + facilityUsageIndex = headerValues.indexOf(headersMap["Facility usage"]); + return; + } + + const facilityCode = row.getCell(facilityCodeIndex).value; + if (facilityCode && mappingData[facilityCode]) { + const facilityDetails = mappingData[facilityCode]; + row.getCell(boundaryCodeIndex).value = + facilityDetails.serviceBoundaries.join(",") || ""; + row.getCell(facilityUsageIndex).value = "Active"; + mappedData[facilityCode] = true; + } else { + row.getCell(boundaryCodeIndex).value = ""; + row.getCell(facilityUsageIndex).value = "Inactive"; + } + }); + + // Handle missing facilities + for (const [facilityCode, facilityDetails] of Object.entries(mappingData)) { + if (!mappedData[facilityCode]) { + missingFacilities.push(facilityCode); + + // Find the first empty row in the sheet + let emptyRowIndex = worksheet.rowCount + 1; // Default to the next available row + for (let i = 1; i <= worksheet.rowCount; i++) { + const row = worksheet.getRow(i); + if (!row.getCell(1).value) { // Assuming column 1 is used to determine emptiness + emptyRowIndex = i; + break; + } + } + + const newRow = worksheet.getRow(emptyRowIndex); + + // Assign values to the identified empty row + newRow.getCell(facilityCodeIndex).value = facilityCode; + newRow.getCell(headerValues.indexOf(headersMap["Facility Name"])).value = + facilityDetails?.additionalDetails?.facilityName; + newRow.getCell(headerValues.indexOf(headersMap["Facility type"])).value = + facilityDetails?.additionalDetails?.facilityType; + newRow.getCell( + headerValues.indexOf(headersMap["Facility status"]) + ).value = facilityDetails?.additionalDetails?.facilityStatus; + newRow.getCell(headerValues.indexOf(headersMap["Capacity"])).value = + facilityDetails?.additionalDetails?.capacity; + newRow.getCell(boundaryCodeIndex).value = + facilityDetails.serviceBoundaries.join(",") || ""; + newRow.getCell(facilityUsageIndex).value = "Active"; + + newRow.commit(); // Save the changes to the row + } + } + + logger.info( + `Updated the boundary & active/inactive status information in facility received from the microplan` + ); + logger.info( + `mapping completed for facility enitity count : ${ + Object.keys(mappedData)?.length + }` + ); + + return worksheet; +} + +function getHeaderIndex( + headers: any, + headerName: string, + localizationMap: any +) { + return headers.indexOf( + getLocalizedName(headerName, localizationMap) + ); +} + +function findAndChangeTargetData( + worksheet: any, + mappingData: any, + headers: any, + localizationMap: any +) { + logger.info( + `Received for Target mapping, enitity count : ${ + Object.keys(mappingData)?.length + }` + ); + + if (headers == null || headers.length == 0) { + throwError("Error", 500, "Mapping not found in MDMS for Campaign"); + } + logger.info( + `Received for Target mapping, headers count : ${ + headers?.length + }` + ); + logger.debug( + `headers: ${getFormattedStringForDebug(headers)}` + ); + let headersInSheet = worksheet.getRow(1).values; + const mappedData: any = {}; + // Iterate through rows in Sheet1 (starting from row 2 to skip the header) + worksheet.eachRow((row: any, rowIndex: number) => { + if (rowIndex === 1) return; // Skip the header row + const column1Value = row.getCell( + getHeaderIndex( + headersInSheet, + config?.boundary?.boundaryCode, + localizationMap + ) + ).value; // Get the value from column 1 + logger.debug( + `column1Value: ${getFormattedStringForDebug(column1Value)}` + ); + if (mappingData?.[column1Value] && headers != null && headers.length > 0) { + // Update columns 5 and 6 if column 1 value matches + headers.forEach((header: any) => { + header.from.forEach((fromValue: any) => { + row.getCell( + getHeaderIndex(headersInSheet, header?.to, localizationMap) + ).value = + mappingData?.[column1Value]?.additionalDetails?.[ + fromValue + ]; + logger.debug( + `headers to: ${getFormattedStringForDebug(getLocalizedName(header?.to, localizationMap))}` + ); + }); + }) + mappedData[column1Value] = rowIndex; + } else { + logger.info(`not doing anything if taregt cel not found`); + // Default values for other rows + // row.getCell(6).value = ""; + // row.getCell(7).value = "Inactive"; + } + }); + logger.info( + `Updated the boundary & active/inactive status information in Target received from the microplan` + ); + logger.info( + `mapping completed for Target enitity count : ${ + Object.keys(mappedData)?.length + }` + ); + logger.info( + `mapping not found for Target entity count : ${ + Object.keys(mappingData)?.length - Object.keys(mappedData)?.length + }` + ); + return worksheet; +} + +const getBoundariesFromCampaign = (CampaignDetails: any = {}) => { + logger.info("fetching all boundaries in that CampaignDetails"); + const boundaries = CampaignDetails?.boundaries?.map((obj: any) => obj?.code); + logger.debug( + `boundaries in that CampaignDetails are :${getFormattedStringForDebug( + boundaries + )}` + ); + return boundaries; +}; + +export const fetchUserData = async (request: any, localizationMap: any) => { + const { tenantId, planConfigurationId, campaignId } = + request.body.MicroplanDetails; + logger.info( + `doing the user data fetch for planConfigurationId: ${planConfigurationId} and campaignId: ${campaignId} ` + ); + const userRoleMapping = await fetchUserRoleMappingFromMDMS(tenantId); + logger.info(`got the user mapping from the plan api`); + const hierarchySchemaDataForConsole = await searchMDMS( + ["console"], + "HCM-ADMIN-CONSOLE.HierarchySchema", + request.body.RequestInfo + ); + const planResponse = await searchPlan( + planConfigurationId, + tenantId, + getBoundariesFromCampaign(request.body.CampaignDetails)?.length + ); + const boundariesOfCampaign = await getBoundaryInformation( + request.body.CampaignDetails, + request.body.CampaignDetails?.hierarchyType, + tenantId + ); + const filteredBoundariesAtWhichUserGetsCreated = + getFilteredBoundariesAtWhichUserGetsCreated( + boundariesOfCampaign, + hierarchySchemaDataForConsole?.mdms + ); + logger.debug( + `boundariesOfCampaign : ${getFormattedStringForDebug(boundariesOfCampaign)}` + ); + + const filteredBoundaryCodeMapWithChildrens = + enrichBoundariesWithTheSelectedChildrens( + boundariesOfCampaign, + filteredBoundariesAtWhichUserGetsCreated + ); + logger.debug( + `filteredBoundaryCodeMapWithChildrens : ${getFormattedStringForDebug( + filteredBoundaryCodeMapWithChildrens + )}` + ); + + const boundaryWithRoleMap = getUserRoleMapWithBoundaryCode( + planResponse, + userRoleMapping + ); + logger.debug( + `created userBoundaryMap :${getFormattedStringForDebug( + boundaryWithRoleMap + )}` + ); + + const consolidatedUserRolesPerBoundary = consolidateUserRoles( + boundaryWithRoleMap, + filteredBoundaryCodeMapWithChildrens + ); + + logger.debug( + `created final consolidatedUserRolesPerBoundary :${getFormattedStringForDebug( + consolidatedUserRolesPerBoundary + )}` + ); + const generatedUserTemplateFileStoreId = await getTheGeneratedResource( + campaignId, + tenantId, + "userWithBoundary", + request.body.CampaignDetails?.hierarchyType + ); + logger.debug( + `downloadresponse userWithBoundary ${getFormattedStringForDebug( + generatedUserTemplateFileStoreId + )}` + ); + const fileUrl = await fetchFileFromFilestore( + generatedUserTemplateFileStoreId, + tenantId + ); + logger.debug( + `downloadresponse userWithBoundary ${getFormattedStringForDebug(fileUrl)}` + ); + + const workbook = await getExcelWorkbookFromFileURL( + fileUrl, + getLocalizedName(config?.user.userTab, localizationMap) + ); + logger.info(`workbook created for user`); + + const updatedWorksheet = await findAndChangeUserData( + workbook.getWorksheet( + getLocalizedName(config?.user.userTab, localizationMap) + ), + consolidatedUserRolesPerBoundary + ); + logger.info( + `workbook updated for user with the data received from microplan` + ); + const responseData = + updatedWorksheet && (await createAndUploadFile(workbook, request)); + logger.info("user File updated successfully:" + JSON.stringify(responseData)); + if (responseData?.[0]?.fileStoreId) { + logger.info( + "user File updated successfully:" + + JSON.stringify( + responseData?.[0]?.fileStoreId + " for campaignid : " + campaignId + ) + ); + } else { + throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); + } + + await updateCampaignDetailsAfterSearch( + request, + { + fileStoreId: responseData?.[0]?.fileStoreId, + id: "not-validated", + }, + "user" + ); + + logger.info( + `updated the resources of user for campaignid : ${campaignId} and planid: ${planConfigurationId} ` + ); +}; + +export async function updateCampaignDetailsAfterSearch( + request: any, + resourceObject: any, + type: string +) { + const { tenantId, campaignId } = request.body.MicroplanDetails; + const campaignDetails = { + tenantId: tenantId, + ids: [campaignId], + }; + const searchedCampaignResponse = await searchProjectTypeCampaignService( + campaignDetails + ); + const searchedCamapignObject = + searchedCampaignResponse?.CampaignDetails?.[0] || null; + if (searchedCamapignObject != null) { + const newRequestBody = { + RequestInfo: request.body.RequestInfo, // Retain the original RequestInfo + CampaignDetails: searchedCamapignObject, // campaigndetails from search response + }; + const req: any = replicateRequest(request, newRequestBody); + // Validate input structure + if (resourceObject) { + let resourceFound = false; // Flag to track if resource is updated + + // Loop through resources to update or append as needed + searchedCamapignObject?.resources?.forEach((resource: any) => { + if (resource.type === type) { + resource.filestoreId = resourceObject?.fileStoreId; + resource.resourceId = resourceObject?.id; + logger.info( + `Updated resource of type ${type} with filestoreId: ${resourceObject.filestoreId}` + ); + resourceFound = true; + } + }); + + // If no resource of the given type was found, append a new one + if (!resourceFound) { + searchedCamapignObject?.resources.push({ + type: type, + filename: `filled-${type}-data-from-microplan.xlsx`, // Dynamically naming based on type + filestoreId: resourceObject?.fileStoreId, + resourceId: resourceObject?.id, + }); + logger.info(`Appended new resource of type ${type}`); + } + req.body.CampaignDetails = searchedCamapignObject; + } else { + console.error( + "Invalid structure in CampaignDetails or fileDetails. Ensure both are non-empty arrays." + ); + } + + // Call external service after updating the campaign details + await updateProjectTypeCampaignService(req); + } else { + throwError( + "CAMPAIGN", + 500, + "CAMPAIGN_SEARCH_ERROR", + "Error in Campaign Search" + ); + } +} + +export async function validateSheet( + request: any, + tenantId: any, + type: any, + fileStoreId: any, + campaignId: any, + hierarchyType: any +) { + let dataCreateBody = { + ResourceDetails: { + tenantId: tenantId, + type: type, + fileStoreId: fileStoreId, + action: "validate", + campaignId: campaignId, + hierarchyType: hierarchyType, + additionalDetails: {}, + }, + }; + + // Now merging defaultRequestInfo *with* dataCreateBody, so both are preserved + const newRequest: any = { + body: { ...request.body, ...dataCreateBody }, // Spread both objects to keep both their properties + }; + + try { + const resourceDetails:any = await createAndPollForCompletion(newRequest); + logger.info(`validation results :: ${resourceDetails?.[0]?.id} & status: ${resourceDetails?.[0]?.status}`) + logger.debug(`Final result:, ${getFormattedStringForDebug(resourceDetails)}`); + return resourceDetails; + } catch (error) { + logger.error( + `Error during resource creation and polling:for type ${type}`, + error + ); + logger.info(`setting resource event it fails for ${type}`); + return [{ ...dataCreateBody?.ResourceDetails, id: "not-validated" }]; + } +} +// sample oundary +//{code: "MICROPLAN_MO", name: "MICROPLAN_MO", parent:"", type: "COUNTRY", isRoot: true, includeAllChildren: false} +const getFilteredBoundariesAtWhichUserGetsCreated = ( + boundaries = [], + hierarchySchemaDataForConsole: any[] +) => { + // setting default value in case data is not present + let consolidateUserAtForConsole = "LOCALITY"; + if (hierarchySchemaDataForConsole?.length > 0) { + consolidateUserAtForConsole = + hierarchySchemaDataForConsole[0]?.data?.consolidateUsersAt; + logger.info( + "Taking value " + + consolidateUserAtForConsole + + " for user at console as it is present in mdms data" + ); + } else { + logger.info( + "Taking default value " + + consolidateUserAtForConsole + + " for user at console as it is not present in mdms data" + ); + } + //add config at which level grouping will happen. hardcoded to loclaity + const filteredBoundariesAtWhichUserGetsCreated = boundaries?.filter( + (boundary: any) => boundary?.type == consolidateUserAtForConsole + ); + logger.info( + `filteredBoundariesAtWhichUserGetsCreated count is ${filteredBoundariesAtWhichUserGetsCreated?.length}` + ); + logger.debug( + `filteredBoundariesAtWhichUserGetsCreated are ${getFormattedStringForDebug( + filteredBoundariesAtWhichUserGetsCreated + )}` + ); + return filteredBoundariesAtWhichUserGetsCreated; +}; + +const getBoundaryInformation = async ( + CampaignDetails: any, + boundaryHierarchy: string, + tenantId: string +) => { + const boundaries = CampaignDetails?.boundaries; + if (boundaries?.some((boundary: any) => boundary?.includeAllChildren)) { + const boundaryResponse = await searchBoundaryRelationshipData( + tenantId, + boundaryHierarchy, + true + ); + logger.info("got the boundary hierarchy response"); + if (boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]) { + logger.info("got the boundary hierarchy response"); + } + + return boundaries; + } +}; + +const enrichBoundariesWithTheSelectedChildrens = ( + allSelectedBoundaries = [], + filteredBoundaries = [] +) => { + const enrichedMap: any = {}; + filteredBoundaries?.map((boundary: any) => { + enrichedMap[boundary?.code] = allSelectedBoundaries?.filter( + (bound: any) => bound.parent == boundary?.code + ); + }); + return enrichedMap; +}; +export async function fetchUserRoleMappingFromMDMS(tenantId: any) { + const MdmsCriteria: MDMSModels.MDMSv1RequestCriteria = { + MdmsCriteria: { + tenantId: tenantId, + moduleDetails: [ + { + moduleName: "HCM-ADMIN-CONSOLE", + masterDetails: [ + { + name: "microplanIntegration", + }, + ], + }, + ], + }, + }; + const data = await searchMDMSDataViaV1Api(MdmsCriteria); + const result: Record = {}; + + if ( + data?.MdmsRes?.["HCM-ADMIN-CONSOLE"]?.microplanIntegration && + Array.isArray(data.MdmsRes["HCM-ADMIN-CONSOLE"].microplanIntegration) + ) { + const integrations = + data.MdmsRes["HCM-ADMIN-CONSOLE"].microplanIntegration; + + integrations.forEach((integration: any) => { + const type = integration.type; + + if (!result[type]) { + result[type] = []; + } + + integration.mappings.forEach((mapping: any) => { + result[type].push({ + to: mapping.to, + from: mapping.from, + filter: mapping.filter, + }); + }); + }); + } + + return result; +} diff --git a/health-services/project-factory/src/server/utils/microplanUtils.ts b/health-services/project-factory/src/server/utils/microplanUtils.ts new file mode 100644 index 00000000000..a188e01d9d3 --- /dev/null +++ b/health-services/project-factory/src/server/utils/microplanUtils.ts @@ -0,0 +1,493 @@ +import { resourceDataStatuses } from "../config/constants"; +import { v4 as uuidv4 } from 'uuid'; +import config from "./../config"; +import { throwError } from "./genericUtils"; +import { httpRequest } from "./request"; +import { callMdmsData, getSheetData } from "./../api/genericApis"; +import { checkIfSourceIsMicroplan, getLocalizedName } from "./campaignUtils"; +import createAndSearch from "../config/createAndSearch"; +import { produceModifiedMessages } from "../kafka/Producer"; +import { searchMDMSDataViaV2Api } from "../api/coreApis"; +import { getCampaignSearchResponse } from "../api/campaignApis"; + + +export const filterData = (data: any) => { + return data.filter((item: any) => { + // Create a shallow copy of the object without `#status#` and `#errorDetails#` + const { '#status#': status, '#errorDetails#': errorDetails, ...rest } = item; + + // Check if only `!row#number!` remains after removing status and errorDetails + const remainingKeys = Object.keys(rest).filter(key => key !== '!row#number!'); + + // Include the item if any other properties exist besides `!row#number!` + return remainingKeys.length > 0; + }); +}; + + + + + +export async function getUserDataFromMicroplanSheet(request: any, fileStoreId: any, tenantId: any, createAndSearchConfig: any, localizationMap?: { [key: string]: string }) { + const fileResponse = await httpRequest(`${config.host.filestore}${config.paths.filestore}/url`, {}, { tenantId, fileStoreIds: fileStoreId }, "get"); + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 500, "DOWNLOAD_URL_NOT_FOUND"); + } + const rolesForMicroplanWithCode = await getRolesForMicroplan(tenantId, localizationMap, true); + const rolesCodeMapping = rolesForMicroplanWithCode.reduce((acc: any, role: any) => { + acc[role.role] = role.code; + return acc; + }, {}); + const userMapping: any = {}; + for (const sheetName of Object.keys(rolesCodeMapping)) { + const dataOfSheet = filterData(await getSheetData(fileResponse?.fileStoreIds?.[0]?.url, sheetName, true, undefined, localizationMap)); + for (const user of dataOfSheet) { + user.role = rolesCodeMapping?.[sheetName]; + user["!sheet#name!"] = sheetName; + const emailKey = getLocalizedName("HCM_ADMIN_CONSOLE_USER_EMAIL_MICROPLAN", localizationMap) + user[emailKey] = user[emailKey]?.text || user[emailKey]; + const phoneNumberKey = getLocalizedName("HCM_ADMIN_CONSOLE_USER_PHONE_NUMBER_MICROPLAN", localizationMap) + if (!userMapping[user[phoneNumberKey]]) { + userMapping[user[phoneNumberKey]] = [user] + } + else { + userMapping[user[phoneNumberKey]].push(user) + } + } + } + const allUserData = getAllUserData(request, userMapping, localizationMap); + return allUserData; +} + +export function getAllUserData(request: any, userMapping: any, localizationMap: any) { + const emailKey = getLocalizedName("HCM_ADMIN_CONSOLE_USER_EMAIL_MICROPLAN", localizationMap); + const nameKey = getLocalizedName("HCM_ADMIN_CONSOLE_USER_NAME_MICROPLAN", localizationMap); + validateInConsistency(request, userMapping, emailKey, nameKey); + validateNationalDuplicacy(request, userMapping, localizationMap); + const dataToCreate: any = []; + for (const phoneNumber of Object.keys(userMapping)) { + const roles = userMapping[phoneNumber].map((user: any) => user.role).join(','); + const email = userMapping[phoneNumber]?.[0]?.[emailKey] || null; + const name = userMapping[phoneNumber]?.[0]?.[nameKey]; + const rowNumbers = userMapping[phoneNumber].map((user: any) => user["!row#number!"]); + const sheetNames = userMapping[phoneNumber].map((user: any) => user["!sheet#name!"]); + const tenantId = request?.body?.ResourceDetails?.tenantId; + const rowXSheet = rowNumbers.map((row: any, index: number) => ({ + row: row, + sheetName: sheetNames[index] + })); + dataToCreate.push({ ["!row#number!"]: rowXSheet, tenantId: tenantId, employeeType: "TEMPORARY", user: { emailId: email, name: name, mobileNumber: phoneNumber, roles: roles } }); + } + request.body.dataToCreate = dataToCreate; + return convertDataSheetWise(userMapping); +} + +function validateInConsistency(request: any, userMapping: any, emailKey: any, nameKey: any) { + const overallInconsistencies: string[] = []; // Collect all inconsistencies here + + enrichInconsistencies(overallInconsistencies, userMapping, nameKey, emailKey); + if (overallInconsistencies.length > 0) { + request.body.ResourceDetails.status = resourceDataStatuses.invalid + } + + request.body.sheetErrorDetails = Array.isArray(request.body.sheetErrorDetails) ? [...request.body.sheetErrorDetails, ...overallInconsistencies] : overallInconsistencies; +} + +function validateNationalDuplicacy(request: any, userMapping: any, localizationMap: any) { + const duplicates: any[] = []; + + for (const phoneNumber in userMapping) { + const roleMap: any = {}; + const users = userMapping[phoneNumber]; + + for (const user of users) { + const userRole = user?.role; + if (userRole?.startsWith("ROOT_")) { + // Trim the role + const trimmedRole = userRole.replace("ROOT_", ""); + + // Check for duplicates in the roleMap + if (roleMap[trimmedRole] && roleMap[trimmedRole]["!sheet#name!"] != user["!sheet#name!"]) { + const errorMessage: any = `An user with ${getLocalizedName(trimmedRole, localizationMap)} role can’t be assigned to ${getLocalizedName(userRole, localizationMap)} role`; + duplicates.push({ rowNumber: user["!row#number!"], sheetName: user["!sheet#name!"], status: "INVALID", errorDetails: errorMessage }); + } else { + roleMap[trimmedRole] = user; + } + } + else { + const trimmedRole = userRole; + const errorMessage: any = `An user with ${getLocalizedName("ROOT_" + trimmedRole, localizationMap)} role can’t be assigned to ${getLocalizedName(userRole, localizationMap)} role`; + if (roleMap[trimmedRole] && roleMap[trimmedRole]["!sheet#name!"] != user["!sheet#name!"]) { + duplicates.push({ rowNumber: user["!row#number!"], sheetName: user["!sheet#name!"], status: "INVALID", errorDetails: errorMessage }); + } else { + roleMap[trimmedRole] = user; + } + } + } + } + if (duplicates.length > 0) { + request.body.ResourceDetails.status = resourceDataStatuses.invalid + } + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...duplicates] : duplicates; +} + +function convertDataSheetWise(userMapping: any) { + const sheetMapping: any = {} + for (const phoneNumber in userMapping) { + const users = userMapping[phoneNumber]; + for (const user of users) { + const sheetName = user["!sheet#name!"]; + if (!sheetMapping[sheetName]) { + sheetMapping[sheetName] = []; + } + sheetMapping[sheetName].push(user); + } + } + return sheetMapping; +} + +function getInconsistencyErrorMessage(phoneNumber: any, userRecords: any) { + // Create the error message mentioning all the records for this phone number + const errors: any = [] + const errorMessage = `User details for the same contact number don't match. Please check the user's name or email ID`; + for (const record of userRecords) { + errors.push({ rowNumber: record.row, sheetName: record.sheet, status: "INVALID", errorDetails: errorMessage }); + } + + return errors +} + +function enrichInconsistencies(overallInconsistencies: any, userMapping: any, nameKey: string, emailKey: string) { + for (const phoneNumber in userMapping) { + if (phoneNumber && phoneNumber != 'undefined') { + const users = userMapping[phoneNumber]; + const userRecords: any[] = []; + + // Collect all user data for this phone number + for (const user of users) { + userRecords.push({ + row: user["!row#number!"], + sheet: user["!sheet#name!"], + name: user[nameKey], + email: user[emailKey] + }); + } + + const errorMessage = getInconsistencyErrorMessage(phoneNumber, userRecords); + + // Check for any inconsistencies by comparing all records with each other + const firstRecord = userRecords[0]; // Take the first record as baseline + const inconsistentRecords = userRecords.filter(record => + record.name !== firstRecord.name || record.email !== firstRecord.email + ); + if (inconsistentRecords.length > 0) { + overallInconsistencies.push(...errorMessage); // Collect all inconsistencies + } + } + } +} + +function lockTillStatus(workbook: any) { + workbook.worksheets.forEach((sheet: any) => { + const statusCell = findStatusColumn(sheet); // Find the status column + + if (!statusCell) { + // Lock the entire sheet if no "#status#" found + sheet.protect('passwordhere', { + selectLockedCells: true, + selectUnlockedCells: false + }); + } else { + // Lock the entire sheet but allow selecting unlocked cells + sheet.protect('passwordhere', { + selectLockedCells: true, + selectUnlockedCells: true // Allow selecting unlocked cells + }); + + // Lock the first row + sheet.getRow(1).eachCell({ includeEmpty: true }, (cell: any) => { + cell.protection = { locked: true }; + }); + + // Lock every column starting from the "#status#" column + const statusColIndex = statusCell.col; + for (let col = statusColIndex; col <= sheet.columnCount; col++) { + sheet.getColumn(col).eachCell({ includeEmpty: true }, (cell: any) => { + cell.protection = { locked: true }; + }); + } + + // Unlock the rest of the sheet (if needed) + sheet.eachRow((row: any, rowIndex: any) => { + if (rowIndex > 1) { // Skip first row + row.eachCell({ includeEmpty: true }, (cell: any) => { + if (cell.col < statusColIndex) { // Unlock cells before the status column + cell.protection = { locked: false }; + } + }); + } + }); + } + }); +} + +export function lockWithConfig(sheet: any) { + for (let row = 1; row <= Number.parseInt(config.values.unfrozeTillRow); row++) { + for (let col = 1; col <= Number.parseInt(config.values.unfrozeTillColumn); col++) { + const cell = sheet.getCell(row, col); + if (!cell.value && cell.value !== 0) { + cell.protection = { locked: false }; + } + } + } + sheet.protect('passwordhere', { selectLockedCells: true, selectUnlockedCells: true }); +} + +function lockAll(workbook: any) { + workbook.worksheets.forEach((sheet: any) => { + lockWithConfig(sheet); + }) +} + + +export function lockSheet(request: any, workbook: any) { + if (request?.body?.ResourceDetails?.type == 'create') { + lockAll(workbook); + } + else { + lockTillStatus(workbook); + } +} + +// Helper function to find the column containing "#status#" +function findStatusColumn(sheet: any) { + let statusCell: any = null; + + // Loop through each row + sheet.eachRow((row: any, rowIndex: any): any => { + // Loop through each cell in the row + row.eachCell((cell: any, colIndex: any) => { + // If "#status#" is found, capture the row and column + if (cell.value === "#status#") { + statusCell = { row: rowIndex, col: colIndex }; + } + }); + + // If the status cell is found, stop further iteration + if (statusCell) { + return false; // This will only break the row loop, not the function + } + }); + + // Return the found statusCell, or null if not found + return statusCell; +} + +export function changeCreateDataForMicroplan(request: any, element: any, rowData: any, localizationMap?: any) { + const type = request?.body?.ResourceDetails?.type; + const activeColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName, localizationMap) : null; + if (type == 'facility') { + const projectType = request?.body?.projectTypeCode; + const facilityCapacityColumn = getLocalizedName(`HCM_ADMIN_CONSOLE_FACILITY_CAPACITY_MICROPLAN_${projectType}`, localizationMap); + if (rowData[facilityCapacityColumn] >= 0) { + element.storageCapacity = rowData[facilityCapacityColumn] + } + if (activeColumnName && rowData[activeColumnName] == "Active") { + if (Array(request?.body?.facilityDataForMicroplan) && request?.body?.facilityDataForMicroplan?.length > 0) { + request.body.facilityDataForMicroplan.push({ ...rowData, facilityDetails: element }) + } + else { + request.body.facilityDataForMicroplan = [{ ...rowData, facilityDetails: element }] + } + } + } +} + +export function updateFacilityDetailsForMicroplan(request: any, createdData: any) { + const facilityDataForMicroplan = request?.body?.facilityDataForMicroplan; + if (Array.isArray(facilityDataForMicroplan) && facilityDataForMicroplan.length > 0) { + for (const element of facilityDataForMicroplan) { + const rowNumber = element['!row#number!']; + const createdDataWithMatchingRowNumber = createdData.find((data: any) => data['!row#number!'] == rowNumber) || null; + if (createdDataWithMatchingRowNumber) { + element.facilityDetails.id = createdDataWithMatchingRowNumber.id + } + } + } +} + + +export async function createPlanFacilityForMicroplan(request: any, localizationMap?: any) { + if (request?.body?.ResourceDetails?.type == 'facility' && request?.body?.ResourceDetails?.additionalDetails?.source == 'microplan') { + const allFacilityDatas = request?.body?.facilityDataForMicroplan; + const planConfigurationId = request?.body?.ResourceDetails?.additionalDetails?.microplanId; + request.body.MicroplanDetails = { + tenantId: request?.body?.ResourceDetails?.tenantId, + planConfigurationId: planConfigurationId + } + const planConfigSearchResponse = await planConfigSearch(request); + const planConfigurationName = planConfigSearchResponse?.PlanConfiguration?.[0]?.name; + for (const element of allFacilityDatas) { + const produceObject: any = getPlanFacilityObject(request, element, planConfigurationName, planConfigurationId, localizationMap); + await produceModifiedMessages(produceObject, config?.kafka?.KAFKA_SAVE_PLAN_FACILITY_TOPIC); + } + } +} + +function getPlanFacilityObject(request: any, element: any, planConfigurationName: any, planConfigurationId: any, localizationMap?: any) { + const residingBoundariesColumn = getLocalizedName(`HCM_ADMIN_CONSOLE_RESIDING_BOUNDARY_CODE_MICROPLAN`, localizationMap); + const singularResidingBoundary = element?.[residingBoundariesColumn] + ? element[residingBoundariesColumn].split(",")[0] + : null; + const facilityStatus = element?.facilityDetails?.isPermanent ? "Permanent" : "Temporary"; + const facilityType = element?.facilityDetails?.usage; + const hierarchyType = request?.body?.ResourceDetails?.hierarchyType; + const currTime = new Date().getTime(); + const planFacilityProduceObject: any = { + PlanFacility: { + id: uuidv4(), + tenantId: element?.facilityDetails?.tenantId, + planConfigurationId: planConfigurationId, + facilityId: element?.facilityDetails?.id, + residingBoundary: singularResidingBoundary, + facilityName: element?.facilityDetails?.name, + serviceBoundaries: null, + planConfigurationName: planConfigurationName, + additionalDetails: { + capacity: element?.facilityDetails?.storageCapacity, + facilityName: element?.facilityDetails?.name, + facilityType: facilityType, + facilityStatus: facilityStatus, + assignedVillages: [], + servingPopulation: 0, + hierarchyType: hierarchyType + }, + active: true, + auditDetails: { + createdBy: request?.body?.RequestInfo?.userInfo?.uuid, + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, + createdTime: currTime, + lastModifiedTime: currTime + } + } + } + const fixedPostColumn = getLocalizedName(`HCM_ADMIN_CONSOLE_FACILITY_FIXED_POST_MICROPLAN`, localizationMap); + if (element?.[fixedPostColumn]) { + planFacilityProduceObject.PlanFacility.additionalDetails.fixedPost = element?.[fixedPostColumn] + } + return planFacilityProduceObject; +} + + +export async function planFacilitySearch(request: any) { + const { tenantId, planConfigurationId } = request.body.MicroplanDetails; + const searchBody = { + RequestInfo: request.body.RequestInfo, + PlanFacilitySearchCriteria: { + tenantId: tenantId, + planConfigurationId: planConfigurationId + } + } + + const searchResponse = await httpRequest(config.host.planServiceHost + config.paths.planFacilitySearch, searchBody); + return searchResponse; +} + +export function planConfigSearch(request: any) { + const { tenantId, planConfigurationId } = request.body.MicroplanDetails; + const searchBody = { + RequestInfo: request.body.RequestInfo, + PlanConfigurationSearchCriteria: { + tenantId: tenantId, + id: planConfigurationId + } + } + + const searchResponse = httpRequest(config.host.planServiceHost + config.paths.planConfigSearch, searchBody); + return searchResponse; +} + +export function modifyBoundaryIfSourceMicroplan(boundaryData: any[], request: any) { + // Check if the request is for a source microplan and the type is 'facilityWithBoundary' + if (request?.body?.isSourceMicroplan && request?.query?.type == 'facilityWithBoundary') { + // Extract the boundary hierarchy from the request body + const hierarchy = request?.body?.hierarchyType?.boundaryHierarchy; + let villageIndex: any; + // Determine the `villageIndex` based on the hierarchy length if present + if (hierarchy) { + // Set `villageIndex` to the last element in the hierarchy (boundary hierarchy depth) + villageIndex = hierarchy?.length - 1; + } else { + // If no hierarchy is provided, calculate the `villageIndex` dynamically + let maxBoundaryDataLength = 0; + + // Iterate through `boundaryData` to find the maximum length of any boundary array + for (const boundary of boundaryData) { + if (boundary?.length > maxBoundaryDataLength) { + maxBoundaryDataLength = boundary?.length; + } + } + + // If boundary data has sufficient depth, set `villageIndex` to the second-to-last level + if (maxBoundaryDataLength >= 2) { + villageIndex = maxBoundaryDataLength - 2; + } + } + // Filter out boundaries that don't have the `villageIndex` + boundaryData = boundaryData.filter((boundary: any) => boundary?.[villageIndex]); + } + return boundaryData; +} + +export async function getRolesForMicroplan(tenantId: string, localizationMap: any, fetchWithRoleCodes: boolean = false) { + const MdmsCriteria: any = { + tenantId: tenantId, + schemaCode: "hcm-microplanning.rolesForMicroplan", + }; + const mdmsResponse: any = await searchMDMSDataViaV2Api(MdmsCriteria); + if (mdmsResponse?.mdms?.length > 0) { + if (fetchWithRoleCodes) { + // return array { role : "role", code : "roleCode" } + return mdmsResponse?.mdms?.filter((role: any) => role?.isActive) + ?.map((role: any) => ({ role: getLocalizedName(role?.data?.roleCode, localizationMap), code: role?.data?.roleCode })); + } + else { + return mdmsResponse?.mdms + ?.filter((role: any) => role?.isActive) // Filter roles with isActive true + ?.map((role: any) => getLocalizedName(role?.data?.roleCode, localizationMap)); // Map to extract the role + } + } + else { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", `Some error occured during rolesForMicroplan mdms search.`); + return []; + } +} + +export async function isMicroplanRequest(request: any): Promise { + const campaignId = request?.query?.campaignId || request?.body?.ResourceDetails?.campaignId; + if (campaignId == "microplan") { + return true; + } + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + return checkIfSourceIsMicroplan(campaignObject); +} + +export async function getReadMeConfigForMicroplan(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}_MICROPLAN`) { + 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 {}; + } +} + diff --git a/health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts b/health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts new file mode 100644 index 00000000000..eeb6c2c8d9d --- /dev/null +++ b/health-services/project-factory/src/server/utils/onGoingCampaignUpdateUtils.ts @@ -0,0 +1,768 @@ +import { searchProjectTypeCampaignService } from "../service/campaignManageService"; +import { getLocalizedHeaders, replicateRequest, throwError } from "./genericUtils"; +import { httpRequest } from "./request"; +import config from "../config/index"; +import { getLocalizedName } from "./campaignUtils"; +import { logger } from "./logger"; +import { callGenerate } from "./generateUtils"; +// import { getCampaignSearchResponse } from "server/api/campaignApis"; +import { getExcelWorkbookFromFileURL } from "./excelUtils"; +import { createAndUploadFile, getSheetData, getTargetSheetData } from "../api/genericApis"; +import { searchDataService } from "../service/dataManageService"; +import { produceModifiedMessages } from "../kafka/Producer"; + +async function getParentCampaignObject(request: any, parentId: any) { + try { + // const searchBodyForParent = { + // RequestInfo: request.body.RequestInfo, + const CampaignDetails = { + tenantId: request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId || request?.body?.CampaignDetails?.tenantId, + ids: [parentId] + } + // }; + // const req: any = replicateRequest(request, searchBodyForParent); + const parentSearchResponse = await searchProjectTypeCampaignService(CampaignDetails); + return parentSearchResponse?.CampaignDetails?.[0]; + } catch (error) { + logger.error("Error fetching parent campaign object:", error); + throwError("CAMPAIGN", 400, "PARENT_CAMPAIGN_ERROR", "Parent Campaign fetching error "); + } +} + +function getCreatedResourceIds(resources: any, type: any) { + const processedType = type === 'boundary' + ? 'boundaryWithTarget' + : (type.includes('With') ? type.split('With')[0] : type); + return resources + .filter((item: any) => item.type === processedType) + .map((item: any) => item.createResourceId); +} + +function buildSearchCriteria(request: any, createdResourceId: any, type: any) { + const processedType = type === 'boundary' + ? 'boundaryWithTarget' + : (type === 'boundaryWithTarget' ? type : (type.includes('With') ? type.split('With')[0] : type)); + + const requestInfo = request?.body + ? request.body.RequestInfo + : { RequestInfo: request?.RequestInfo }; + return { + RequestInfo: requestInfo, + SearchCriteria: { + id: createdResourceId, + tenantId: request?.query?.tenantId || request?.CampaignDetails?.tenantId, + type: processedType + } + }; +} + +async function fetchFileUrls(request: any, processedFileStoreIdForUSerOrFacility: any) { + try { + const reqParamsForFetchingFile = { + tenantId: request?.query?.tenantId, + fileStoreIds: processedFileStoreIdForUSerOrFacility + }; + return await httpRequest( + `${config?.host?.filestore}${config?.paths?.filestorefetch}`, + request?.body, + reqParamsForFetchingFile, + "get" + ); + } catch (error) { + logger.error("Error fetching file URLs:", error); + throw error; + } +} + + + +function modifyProcessedSheetData(type: any, sheetData: any, schema: any, localizationMap?: any) { + if (!sheetData || sheetData.length === 0) return []; + + const originalHeaders = type === config?.facility?.facilityType ? [config?.facility?.facilityCodeColumn, ...schema?.columns] : schema?.columns; + + let localizedHeaders = getLocalizedHeaders(originalHeaders, localizationMap); + + // Map each object in sheetData to an array of values corresponding to the header order + let dataRows = sheetData.map((row: any) => { + return localizedHeaders.map((header: any) => row[header] || ''); + }); + + const updatedHeaders = localizedHeaders.map((header: any) => header === getLocalizedName(config?.boundary?.boundaryCodeMandatory, localizationMap) ? + getLocalizedName(config?.boundary?.boundaryCodeOld, localizationMap) : header) + + const updatedWithAdditionalHeaders = [...updatedHeaders, config?.boundary?.boundaryCodeMandatory] + localizedHeaders = getLocalizedHeaders(updatedWithAdditionalHeaders, localizationMap); + + dataRows = dataRows.map((row: any, index: number) => { + const boundaryCodeValue = sheetData[index][getLocalizedName(config?.boundary?.boundaryCodeMandatory, localizationMap)] || ''; + return [...row, boundaryCodeValue]; + }); + + // Combine headers and dataRows + const modifiedData = [localizedHeaders, ...dataRows]; + + return modifiedData; +} + +function freezeUnfreezeColumnsForProcessedFile(sheet: any, columnsToFreeze: number[], columnsToUnfreeze: number[]) { + // First, unfreeze specified columns + columnsToUnfreeze.forEach(colNumber => { + for (let row = 1; row <= sheet.rowCount; row++) { + const cell = sheet.getCell(row, colNumber); + cell.protection = { locked: false }; // Unfreeze the cell + } + }); + + // Then, freeze specified columns + columnsToFreeze.forEach(colNumber => { + for (let row = 1; row <= sheet.rowCount; row++) { + const cell = sheet.getCell(row, colNumber); + cell.protection = { locked: true }; // Freeze the cell + } + }); +} + + +function getColumnIndexByHeader(sheet: any, headerName: string): number { + // Get the first row (assumed to be the header row) + const firstRow = sheet.getRow(1); + + // Find the column index where the header matches the provided name + for (let col = 1; col <= firstRow.cellCount; col++) { + const cell = firstRow.getCell(col); + if (cell.value === headerName) { + return col; // Return the column index (1-based) + } + } + return 1; +} + +// function validateBoundaryCodes(activeRows: any, localizationMap?: any) { +// const updatedBoundaryCodeKey = getLocalizedName('HCM_ADMIN_CONSOLE_UPDATED_BOUNDARY_CODE', localizationMap); +// const updatedBoundaryCodeValue = activeRows[updatedBoundaryCodeKey]; +// const boundaryCodeMandatoryKey = getLocalizedName("HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY", localizationMap); +// const boundaryCodeMandatoryValue = activeRows[boundaryCodeMandatoryKey]; +// if (!updatedBoundaryCodeValue && !boundaryCodeMandatoryValue) { +// const errorDetails = { +// errors: [ +// { +// instancePath: '', +// schemaPath: '#/required', +// keyword: 'required', +// params: { +// missingProperty: `${updatedBoundaryCodeKey} and ${boundaryCodeMandatoryKey} both` +// }, +// message: `must have required properties ${`${updatedBoundaryCodeKey}, ${boundaryCodeMandatoryKey}`}` +// } +// ] +// }; + +// throw new Error(JSON.stringify(errorDetails)); +// } +// } + +async function checkAndGiveIfParentCampaignAvailable(request: any, campaignObject: any) { + if (campaignObject?.parentId) { + logger.info("enriching the parent campaign details for update flow"); + const parentCampaignObject = await getParentCampaignObject(request, campaignObject.parentId); + + if (parentCampaignObject?.status === "created" && !parentCampaignObject.isActive) { + request.body.parentCampaignObject = parentCampaignObject; + } + } +} + +function hideColumnsOfProcessedFile(sheet: any, columnsToHide: any[]) { + columnsToHide.forEach((column) => { + if (column > 0) { + sheet.getColumn(column).hidden = true; + } + }); +} + +function unhideColumnsOfProcessedFile(sheet: any, columnsToUnide: any) { + columnsToUnide.forEach((column: any) => { + if (column) { + sheet.getColumn(column).hidden = false; + } + }); +} + +function modifyNewSheetData(processedDistrictSheetData: any, newSheetData: any, headers: any, oldTargetColumnsToHide: any[], localizationMap?: any) { + let modifiedData = []; + const localizedHeaders = getLocalizedHeaders(headers, localizationMap); + if (processedDistrictSheetData && processedDistrictSheetData.length > 0) { + const dataRows = processedDistrictSheetData.map((row: any) => { + return localizedHeaders.map((header: any) => row[header] || ''); + }); + modifiedData = [localizedHeaders, ...dataRows]; + } else { + // If processedDistrictSheetData is not present, work only with newSheetData + modifiedData = [newSheetData]; + } + + const newData = updateTargetValues(modifiedData, newSheetData, localizedHeaders, oldTargetColumnsToHide, localizationMap); + return newData; +} + + +function updateTargetValues(originalData: any, newData: any, localizedHeaders: any, oldTargetColumnsToHide: any[], localizationMap?: any) { + + const boundaryCodeIndex = localizedHeaders.indexOf(getLocalizedName(config?.boundary?.boundaryCode, localizationMap)); + + // Update newData with matching values from originalData + newData = newData.map((newRow: any) => { + const matchingRow = originalData.find((originalRow: any) => + originalRow.slice(0, boundaryCodeIndex + 1).every((val: any, index: any) => val === newRow[index]) + ); + + return newRow.map((value: any, index: any) => + index > boundaryCodeIndex && matchingRow && value === '' + ? matchingRow[index] + : value + ); + }); + newData = newData.map((newRow: any, rowIndex: number) => { + const updatedValues: any[] = []; + for (let i = boundaryCodeIndex + 1; i < localizedHeaders.length; i++) { + updatedValues.push(newRow[i]); // Store original value + if (rowIndex === 0) { // Only modify the first row + const modifiedValue = `${newRow[i]}(OLD)`; // Create modified value with (OLD) suffix + newRow[i] = modifiedValue; // Update newRow[i] with the modified value + oldTargetColumnsToHide.push(modifiedValue); // Push the modified value + } + } + // Concatenate original values at the end of every row + return [...newRow, ...updatedValues]; + }); + return newData; +} + +function validateBoundariesIfParentPresent(request: any) { + const { parentCampaign, CampaignDetails } = request?.body || {}; + + if (parentCampaign) { + const errors: string[] = []; + const newBoundaries: any[] = []; + const parentCampaignBoundaryCodes = parentCampaign.boundaries.map((boundary: any) => boundary.code); + + CampaignDetails?.boundaries?.forEach((boundary: any) => { + if (parentCampaignBoundaryCodes.includes(boundary.code)) { + errors.push(boundary.code); + } else { + if (!boundary?.isRoot) { + newBoundaries.push(boundary); + } else { + throwError( + "COMMON", + 400, + "VALIDATION_ERROR", + `Boundary with code ${boundary.code} cannot be added as it is marked as root. Root boundary should come from the parent campaign.` + ); + } + } + }); + + if (errors.length > 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary Codes found already in Parent Campaign: ${errors.join(', ')}`); + } + request.body.boundariesCombined = [...parentCampaign.boundaries, ...newBoundaries]; + } + else { + request.body.boundariesCombined = request?.body?.CampaignDetails?.boundaries + } +} + + +async function callGenerateWhenChildCampaigngetsCreated(request: any) { + try { + const newRequestBody = { + RequestInfo: request?.body?.RequestInfo, + Filters: { + boundaries: request?.body?.boundariesCombined + } + }; + + 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}`); + } +} + + +function getBoundariesArray(parentCampaignBoundaries: any, campaignBoundaries: any) { + // Ensure both inputs are arrays or default to empty arrays + const validParentBoundaries = Array.isArray(parentCampaignBoundaries) ? parentCampaignBoundaries : []; + const validCampaignBoundaries = Array.isArray(campaignBoundaries) ? campaignBoundaries : []; + + return [...validParentBoundaries, ...validCampaignBoundaries]; +} + +async function getBoundariesFromCampaignSearchResponse(request: any, campaignDetails: any) { + let parentCampaignBoundaries: any[] = []; + if (campaignDetails?.parentId) { + const parentCampaignObject = await getParentCampaignObject(request, campaignDetails?.parentId); + parentCampaignBoundaries = parentCampaignObject?.boundaries; + } + return getBoundariesArray(parentCampaignBoundaries, campaignDetails?.boundaries) +} + +async function fetchProjectsWithProjectId(request: any, projectId: any, tenantId: any) { + const projectSearchBody = { + RequestInfo: request?.body?.RequestInfo || request?.RequestInfo, + Projects: [ + { + id: projectId, + tenantId: tenantId + } + ] + } + const projectSearchParams = { + tenantId: tenantId, + offset: 0, + limit: 1, + includeDescendants: true + } + logger.info("Project search params " + JSON.stringify(projectSearchParams)) + const projectSearchResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectSearch, projectSearchBody, projectSearchParams); + if (projectSearchResponse?.Project && Array.isArray(projectSearchResponse?.Project) && projectSearchResponse?.Project?.length > 0) { + return projectSearchResponse; + } + else { + throwError("PROJECT", 500, "PROJECT_SEARCH_ERROR") + return [] + } +} + + +async function fetchProjectsWithBoundaryCodeAndReferenceId(boundaryCode: any, tenantId: any, referenceId: any, RequestInfo?: any) { + try { + const projectSearchBody = { + RequestInfo: RequestInfo, + Projects: [ + { + address: { + boundary: boundaryCode, + }, + tenantId: tenantId, + referenceID: referenceId + } + ] + } + const projectSearchParams = { + tenantId: tenantId, + offset: 0, + limit: 1 + } + logger.info("Project search params " + JSON.stringify(projectSearchParams)) + const projectSearchResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectSearch, projectSearchBody, projectSearchParams); + if (projectSearchResponse?.Project && Array.isArray(projectSearchResponse?.Project) && projectSearchResponse?.Project?.length > 0) { + return projectSearchResponse; + } + else { + return null; + } + } catch (error: any) { + throwError("PROJECT", 500, "PROJECT_SEARCH_ERROR") + } +} + +function getBoundaryProjectMappingFromParentCampaign(request: any, project: any) { + + const boundarySet = new Set(); + + // Initialize result array with the project itself (id and boundary) + const result = [ + { + id: project.id, + boundary: project.address.boundary + }, + ...project.descendants.map((descendant: any) => ({ + id: descendant.id, + boundary: descendant.address.boundary + })) + ]; + + // Iterate over the result array to find matching boundaries and populate projectId + result.forEach((entry: any) => { + const boundary = entry.boundary; + boundarySet.add(boundary); + // Initialize the boundaryProjectMapping for this boundary if not present + if (!request?.body?.boundaryProjectMapping?.[boundary]) { + request.body.boundaryProjectMapping[boundary] = { parent: null, projectId: null }; + } + // Update the projectId in the request's boundaryProjectMapping + request.body.boundaryProjectMapping[boundary].projectId = entry.id; + }); + + return boundarySet; +} + + +async function fetchProjectFacilityWithProjectId(request: any, projectId: any, facilityId: any) { + try { + const { tenantId } = request?.body?.parentCampaign || request?.parentCampaign; + const projectSearchBody = { + RequestInfo: request?.body?.RequestInfo || request?.RequestInfo, + ProjectFacility: { + projectId: [ + projectId + ], + facilityId: [ + facilityId + ] + } + } + const projectSearchParams = { + tenantId: tenantId, + offset: 0, + limit: 1 + } + logger.info("Project search params " + JSON.stringify(projectSearchParams)) + const projectFacilitySearchResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectFacilitySearch, projectSearchBody, projectSearchParams); + + if (projectFacilitySearchResponse?.ProjectFacilities && Array.isArray(projectFacilitySearchResponse?.ProjectFacilities) && projectFacilitySearchResponse?.ProjectFacilities?.length > 0) { + return projectFacilitySearchResponse; + } + else { + return null + } + } catch (error: any) { + throwError("PROJECT", 500, "PROJECT_FACILTY_SEARCH_ERROR") + } +} + + +async function fetchProjectStaffWithProjectId(request: any, projectId: any, staffId: any) { + try { + const { tenantId } = request?.body?.parentCampaign || request?.parentCampaign; + const projectSearchBody = { + RequestInfo: request?.body?.RequestInfo || request?.RequestInfo, + ProjectStaff: { + projectId: [ + projectId + ], + staffId: [ + staffId + ] + } + } + + const projectSearchParams = { + tenantId: tenantId, + offset: 0, + limit: 1 + } + logger.info("Project search params " + JSON.stringify(projectSearchParams)) + const projectStaffSearchResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectStaffSearch, projectSearchBody, projectSearchParams); + if (projectStaffSearchResponse?.ProjectStaff && Array.isArray(projectStaffSearchResponse?.ProjectStaff) && projectStaffSearchResponse?.ProjectStaff?.length > 0) { + return projectStaffSearchResponse; + } + else { + return null + } + } catch (error: any) { + throwError("PROJECT", 500, "PROJECT_STAFF_SEARCH_ERROR") + } + +} + +async function delinkAndLinkResourcesWithProjectCorrespondingToGivenBoundary(resource: any, messageObject: any, boundaryCode: any, uniqueIdentifier: any, isDelink: boolean) { + const projectResponse = await fetchProjectsWithBoundaryCodeAndReferenceId(boundaryCode, messageObject?.parentCampaign?.tenantId, messageObject?.CampaignDetails?.campaignNumber, messageObject?.RequestInfo); + let matchingProjectObject: any; + if (projectResponse) { + matchingProjectObject = projectResponse?.Project[0]; + } + const matchingProjectId = matchingProjectObject?.id; + if (!matchingProjectId) { + return false; // No matching project found + } + + + if (resource?.type === "facility") { + const projectFacilityResponse = await fetchProjectFacilityWithProjectId(messageObject, matchingProjectId, uniqueIdentifier); + if (projectFacilityResponse) { + if (isDelink) { + await deleteProjectFacilityMapping(messageObject, projectFacilityResponse) + } + return true; + } else { + return false; + } + } + if (resource?.type === 'user') { + const projectStaffResponse = await fetchProjectStaffWithProjectId(messageObject, matchingProjectId, uniqueIdentifier); + if (projectStaffResponse) { + if (isDelink) { + await deleteProjectStaffMapping(messageObject, projectStaffResponse) + } + return true; + } else { + return false; + } + } + else return false; +} + + +async function deleteProjectFacilityMapping(messageObject: any, projectFacilityResponse: any) { + const projectFacilityDeleteBody = { + RequestInfo: messageObject?.RequestInfo, + ProjectFacilities: [ + projectFacilityResponse?.ProjectFacilities[0] + ] + } + try { + await httpRequest(config?.host?.projectHost + config?.paths?.projectFacilityDelete, projectFacilityDeleteBody); + } + catch (error: any) { + throwError("PROJECT", 500, "PROJECT_FACILITY_DELETE_ERROR") + } +} + +async function deleteProjectStaffMapping(messageObject: any, projectStaffResponse: any) { + const projectStaffDeleteBody = { + RequestInfo: messageObject?.RequestInfo, + ProjectStaff: [ + projectStaffResponse?.ProjectStaff[0] + ] + } + try { + await httpRequest(config?.host?.projectHost + config?.paths?.projectStaffDelete, projectStaffDeleteBody); + } + catch (error: any) { + throwError("PROJECT", 500, "PROJECT_STAFF_DELETE_ERROR") + } +} + + +async function getParentAndCurrentFileUrl(mappingObject: any, resource: any, parentResource: any) { + const parentCreateResourceId = parentResource?.createResourceId ? [parentResource.createResourceId] : []; + const parentResourceSearchResponse = await getResourceFromResourceId(mappingObject, parentCreateResourceId, parentResource); + const parentProcessedFileStoreId = parentResourceSearchResponse?.[0]?.processedFilestoreId; + + const currentCreateResourceId = resource?.createResourceId ? [resource.createResourceId] : []; + const currentResourceSearchResponse = await getResourceFromResourceId(mappingObject, currentCreateResourceId, resource); + const currentProcessedFileStoreId = currentResourceSearchResponse?.[0]?.processedFilestoreId; + + const currentFileUrl = await getFileUrl(currentProcessedFileStoreId, mappingObject?.CampaignDetails?.tenantId); + const parentFileUrl = await getFileUrl(parentProcessedFileStoreId, mappingObject?.CampaignDetails?.tenantId); + + return { currentFileUrl, parentFileUrl }; +} + +function findParentResource(resource: any, resourcesArrayFromParentCampaign: any) { + return resourcesArrayFromParentCampaign.find( + (parentResource: any) => parentResource.type === resource.type + ); +} + +async function getHeadersAccordingToWhichWeReorder(parentWorkbook: any, resource: any) { + + // Determine the sheet name dynamically based on resource type + const headerSourceSheetName: any = resource?.type === 'boundaryWithTarget' + ? parentWorkbook.worksheets[2]?.name // Use the third sheet for 'boundaryWithTarget' type + : parentWorkbook.worksheets[1]?.name; // Use the second sheet for other types + + const sheet = parentWorkbook.getWorksheet(headerSourceSheetName); + if (!sheet) { + throw new Error(`Sheet with name "${headerSourceSheetName}" not found`); + } + + // Get the first row (assuming it's the header row) + const headerRow = sheet.getRow(1); + // Get the first row (assuming it's the header row) + if (!headerRow || headerRow.cellCount === 0) { + throw new Error(`Header row is empty in sheet "${headerSourceSheetName}"`); + } + const headers: any = []; + + headerRow.eachCell((cell: any) => { + headers.push(cell.value); // Collect header cell values + }); + + return headers; +} + + + +async function addDataToWorkbook(currentWorkbook: any, parentWorkbook: any, currentFileUrl: any, resource: any, headersAccordingToWhichWeReorder: any) { + const currentSheet = currentWorkbook.worksheets[1]; + if (resource?.type === 'boundaryWithTarget') { + const boundaryWithTargetSheetData = await getTargetSheetData(currentFileUrl, false, false); + const sheetNames = Object.keys(boundaryWithTargetSheetData); // Get sheet names + for (let i = 2; i < sheetNames.length; i++) { // Start from index 2 for the third sheet + const sheetName = sheetNames[i]; + const sheetData = boundaryWithTargetSheetData[sheetName]; + + // Reorder each row in the current sheet's data + const reorderedData = sheetData.map((row: any) => { + // Map each header in `targetHeaders` to the corresponding value in `row`, + // or set to an empty string if the header is missing + return headersAccordingToWhichWeReorder.map((header: any) => row[header] || ""); + }); + + await addConsolidatedDataToSheet(parentWorkbook, sheetName, headersAccordingToWhichWeReorder, reorderedData); + } + } else { + // Perform further processing using the filestoreId + const currentSheetData: any = await getSheetData(currentFileUrl, currentSheet.name, false) + + const reorderedData = currentSheetData.map((row: any) => { + // Map each header in `targetHeaders` to the corresponding value in the row, + // or set to an empty string if the header is missing in the row + return headersAccordingToWhichWeReorder.map((header: any) => row[header] || ""); + }); + + await addConsolidatedDataToSheet(parentWorkbook, currentSheet.name, headersAccordingToWhichWeReorder, reorderedData); + } +} + + +async function finalizeAndUpload(newWorkbook: any, mappingObject: any, resource: any) { + const responseData = await createAndUploadFile(newWorkbook, mappingObject, mappingObject?.CampaignDetails?.tenantId); + const fileStoreId = responseData?.[0]?.fileStoreId; + const resourceDetails = (await getResourceFromResourceId(mappingObject, [resource.createResourceId], resource))[0]; + resourceDetails.processedFilestoreId = fileStoreId; + resourceDetails.processedFileStoreId = resourceDetails.processedFilestoreId; + resourceDetails.processedFilestoreId = undefined; + + const persistMessage: any = { ResourceDetails: resourceDetails }; + await produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC); +} + + + + +async function processIndividualResource(mappingObject: any, resource: any, resourcesArrayFromParentCampaign: any) { + const parentResource = findParentResource(resource, resourcesArrayFromParentCampaign); + const fileUrls = await getParentAndCurrentFileUrl(mappingObject, resource, parentResource); + + const parentWorkbook = await getExcelWorkbookFromFileURL(fileUrls.parentFileUrl); + const currentWorkbook = await getExcelWorkbookFromFileURL(fileUrls.currentFileUrl) + + const headersAccordingToWhichWeReorder = await getHeadersAccordingToWhichWeReorder(parentWorkbook, resource); + await addDataToWorkbook(currentWorkbook, parentWorkbook, fileUrls?.currentFileUrl, resource, headersAccordingToWhichWeReorder); + + await finalizeAndUpload(parentWorkbook, mappingObject, resource); +} + + +function mergeParentResources(mappingObject: any, resources: any[], resourcesArrayFromParentCampaign: any[]) { + for (const resource of resourcesArrayFromParentCampaign) { + if (!resources.some((r: any) => r.type === resource.type)) { + resources.push(resource); + } + } + mappingObject.CampaignDetails.campaignDetails.resources = resources; +} + +async function processResources(mappingObject: any) { + + const resources = mappingObject?.CampaignDetails?.resources; + const resourcesArrayFromParentCampaign = mappingObject?.parentCampaign?.resources; + + for (const resource of resources) { + try { + await processIndividualResource(mappingObject, resource, resourcesArrayFromParentCampaign); + } catch (error: any) { + throwError("CAMPAIGN", 500, "RESOURCES_CONSOLIDATION_ERROR", + `Error occurred while consolidating resource of type ${resource.type}: ${error.message}`); + } + } + + mergeParentResources(mappingObject, resources, resourcesArrayFromParentCampaign); +} + +async function getResourceFromResourceId(mappingObject: any, createResourceId: any, resource: any) { + const searchCriteria = buildSearchCriteria(mappingObject, createResourceId, resource?.type); + const requestBody = replicateRequest(mappingObject, searchCriteria); + const responseFromDataSearch = await searchDataService(requestBody); + return responseFromDataSearch; +} + + +async function addConsolidatedDataToSheet(parentWorkbook: any, sheetName: string, targetHeaders: string[], reorderedData: any[]) { + // Get or create a worksheet + let sheet = parentWorkbook.getWorksheet(sheetName); + if (!sheet) { + sheet = parentWorkbook.addWorksheet(sheetName); + sheet.addRow(targetHeaders); + } + if (sheet.rowCount > 1) { + // Clear all existing row data starting from the second row + for (let i = 2; i <= sheet.rowCount; i++) { + sheet.getRow(i).values = []; + } + } + + // Overwrite cleared rows with new data + reorderedData.forEach((row, index) => { + const targetRow = sheet.getRow(index + 2); // Start from the second row + targetRow.values = row; // Add the row's values + }); + +} + + +async function getFileUrl(fileStoreId: any, tenantId: any) { + const fileResponse = await httpRequest( + `${config.host.filestore}${config.paths.filestore}/url`, + {}, + { tenantId, fileStoreIds: fileStoreId }, + "get" + ); + + if (!fileResponse || !fileResponse.fileStoreIds || !fileResponse.fileStoreIds[0] || !fileResponse.fileStoreIds[0].url) { + throwError("FILE", 400, "INVALID_FILE"); + } else { + return fileResponse.fileStoreIds[0].url; + } +} + + + + +export { + getParentCampaignObject, + getCreatedResourceIds, + buildSearchCriteria, + fetchFileUrls, + modifyProcessedSheetData, + freezeUnfreezeColumnsForProcessedFile, + getColumnIndexByHeader, + checkAndGiveIfParentCampaignAvailable, + hideColumnsOfProcessedFile, + unhideColumnsOfProcessedFile, + modifyNewSheetData, + validateBoundariesIfParentPresent, + callGenerateWhenChildCampaigngetsCreated, + getBoundariesFromCampaignSearchResponse, + fetchProjectsWithProjectId, + getBoundaryProjectMappingFromParentCampaign, + fetchProjectFacilityWithProjectId, + fetchProjectsWithBoundaryCodeAndReferenceId, + delinkAndLinkResourcesWithProjectCorrespondingToGivenBoundary, + processResources +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/utils/pollUtils.ts b/health-services/project-factory/src/server/utils/pollUtils.ts new file mode 100644 index 00000000000..afba8042988 --- /dev/null +++ b/health-services/project-factory/src/server/utils/pollUtils.ts @@ -0,0 +1,193 @@ +import { defaultRequestInfo } from "../api/coreApis"; // Import default request metadata +import { getFormattedStringForDebug, logger } from "./logger"; // Import logger for logging information and errors +import { createDataService, downloadDataService, searchDataService } from "../service/dataManageService"; +import { throwError } from "./genericUtils"; + +/** + * Downloads a campaign template based on campaign ID, tenant ID, type, and hierarchy. + * @param campaignId The unique identifier for the campaign. + * @param tenantId The tenant identifier for which the template is downloaded. + * @param type The type of the template to be downloaded. + * @param hierarchy The hierarchy type associated with the campaign. + * @returns The response containing the template download details. + */ +export const downloadTemplate = async ( + campaignId: string, + tenantId: string, + type: string, + hierarchy: string +) => { + const searchBody = { + ...defaultRequestInfo, // Include default request metadata + }; + + const params = { + tenantId: tenantId, // Tenant information for the request + type: type, // Specify the template type + hierarchyType: hierarchy, // Specify the hierarchy type + campaignId: campaignId, // Campaign identifier + }; + + logger.info( + `Received a request to download the template for campaign ID: ${campaignId} & type: ${type} ` + ); + const request: any = { + body: { ...searchBody }, + query: { ...params } + } + + const downloadResponse: any = await downloadDataService(request); + + logger.debug(`Received response : ${getFormattedStringForDebug(downloadResponse)}`); + return downloadResponse; // Return the API response containing template details +}; + +/** + * Polls a function at regular intervals until a condition is met or the maximum retries are reached. + * @param functionToBePolledFor The function to be executed for polling. + * @param conditionForTermination A callback function that evaluates whether polling should stop. + * @param pollInterval The interval (in milliseconds) between each poll attempt. Default is 2000ms. + * @param maxRetries The maximum number of retries before terminating polling. Default is 50. + * @returns A promise that resolves with the function response if the condition is met, or rejects if retries are exhausted. + */ +const pollForTemplateGeneration = async ( + functionToBePolledFor: Function, + conditionForTermination: Function, + pollInterval: number = 2500, + maxRetries: number = 20 +) => { + let retries = 0; // Initialize the retry counter + logger.info("received a request for Polling "); + if (!functionToBePolledFor || !conditionForTermination) { + return null; + } + logger.info("request was valid so Polling "); + + return new Promise((resolve, reject) => { + const poll = async () => { + try { + if (retries >= maxRetries) { + // Reject if maximum retries are reached + reject(new Error("Max retries reached")); + return; + } + + const functionResponse = await functionToBePolledFor(); // Execute the polling function + + if (conditionForTermination(functionResponse)) { + // Check if the termination condition is met + logger.info("Polling completed"); + resolve(functionResponse); + return; + } else { + // Increment retries and continue polling after the specified interval + retries++; + logger.info("Polling continuing"); + setTimeout(poll, pollInterval); + } + } catch (error) { + // Handle errors by retrying after the specified interval + retries++; + setTimeout(poll, pollInterval); + } + }; + + // Start polling + poll().catch(reject); + + // Set a timeout to ensure the entire polling operation doesn't exceed a maximum duration + const timeoutDuration = (maxRetries + 1) * pollInterval; + setTimeout(() => { + if (retries < maxRetries) { + logger.error("Polling timeout: Max retries reached"); + reject(new Error("Polling timeout: Max retries reached")); + } + }, timeoutDuration); + }); +}; + + + +const conditionForTermination = (downloadResponse: any) => { + logger.info(`current status ${downloadResponse?.[0]?.status}`) + return downloadResponse?.[0]?.status === "completed" && downloadResponse?.[0]?.fileStoreid; +} + +const conditionForTermination2 = (downloadResponse: any) => { + logger.info(`current status ${downloadResponse?.[0]?.status}`) + return downloadResponse?.[0]?.status === "completed" && downloadResponse?.[0]?.processedFilestoreId; +} + +export const createAndPollForCompletion = async (request: any) => { + try { + // Step 1: Create data + logger.info("Creating data..."); + const resourceDetails = await createDataService(request); + const resourceId = resourceDetails?.id; + + if (!resourceId) { + throwError("DATA", 500, "DATA_CREATE_ERROR", `Failed to retrieve resource ID from creation response for type ${request?.body?.ResourceDetails?.type}`); + } + + logger.info(`Created resource with ID: ${resourceId} of type ${request?.body?.ResourceDetails?.type}`); + + // Step 2: Poll for completion + const polledResponse = await pollForTemplateGeneration( + () => searchData(resourceId, request?.body?.ResourceDetails?.tenantId, request?.body?.ResourceDetails?.type), + conditionForTermination2, + 3000, + 30 + ); + + logger.info("Polling completed successfully", polledResponse); + return polledResponse; + } catch (error: any) { + logger.error("Error during creation or polling", error); + throw error; + } +}; + + + +async function searchData(resourceId: any, tenantId: any, type: any) { + const SearchCriteria = { + id: [resourceId], + tenantId: tenantId, + type: type + }; + const searchBody = { ...defaultRequestInfo, SearchCriteria } + const request: any = { + body: { ...searchBody } + } + + const searchResponse: any = await searchDataService(request); + return searchResponse; +} + + + +export const getTheGeneratedResource = async ( + campaignId: string, + tenantId: string, + type: string, + hierarchy: string +) => { + try { + // Await the response from polling for template generation + const polledResponse: any = await pollForTemplateGeneration( + () => downloadTemplate(campaignId, tenantId, type, hierarchy), + conditionForTermination + ); + + // Log the polled response for debugging + logger.debug(polledResponse); + logger.debug(`polledResponse : ${getFormattedStringForDebug(polledResponse)}`); + + // Return the fileStoreid from the response, ensuring the correct format + return polledResponse?.[0]?.fileStoreid; + + } catch (error: any) { + // Log any error that occurs during polling or processing + logger.error(`Error while fetching the generated resource: ${error?.message}`); + } +} 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/redisUtils.ts b/health-services/project-factory/src/server/utils/redisUtils.ts index f62177928d9..320705df1d6 100644 --- a/health-services/project-factory/src/server/utils/redisUtils.ts +++ b/health-services/project-factory/src/server/utils/redisUtils.ts @@ -1,5 +1,6 @@ import Redis from "ioredis"; import config from "../config"; +import { logger } from "./logger"; const redis = new Redis({ host: config.host.redisHost, @@ -18,12 +19,59 @@ const redis = new Redis({ async function checkRedisConnection(): Promise { try { - await redis.ping(); + if (config?.cacheValues?.cacheEnabled) { + await redis.ping(); + } return true; + } catch (error) { console.error("Redis connection error:", error); return false; } } -export { redis, checkRedisConnection }; +// Listen for the 'connect' event +redis.on('connect', () => { + logger.info(`Successfully connected to Redis! host :: ${config.host.redisHost} & port :: ${config.cacheValues.redisPort}`); + // You can add additional code here to perform actions after a successful connection +}); + +// Listen for errors +redis.on('error', (err) => { + logger.info(`failed connecting to Redis! host :: ${config.host.redisHost} & port :: ${config.cacheValues.redisPort}`); + logger.error("Redis connection error:", err); +}); + + + +async function deleteRedisCacheKeysWithPrefix(prefix: any) { + try { + // Use SCAN instead of KEYS to avoid performance issues + let cursor = '0'; + let keysToDelete: any = []; + + do { + const result = await redis.scan(cursor, 'MATCH', `${prefix}*`, 'COUNT', '100'); + cursor = result[0]; + const keys = result[1]; + + if (keys.length > 0) { + keysToDelete = keysToDelete.concat(keys); + logger.info("Cache keys found to be deleted: " + keys); + } + } while (cursor !== '0'); + + if (keysToDelete.length > 0) { + await redis.del(...keysToDelete); + logger.info(`Deleted keys with prefix "${prefix}":`, keysToDelete); + } else { + logger.info(`No keys found with prefix "${prefix}"`); + } + } catch (error) { + logger.info("Error deleting keys:", error); + throw error; + } +} + + +export { redis, checkRedisConnection, deleteRedisCacheKeysWithPrefix }; diff --git a/health-services/project-factory/src/server/utils/request.ts b/health-services/project-factory/src/server/utils/request.ts index ef23426cc0e..88ea55b52c3 100644 --- a/health-services/project-factory/src/server/utils/request.ts +++ b/health-services/project-factory/src/server/utils/request.ts @@ -47,6 +47,7 @@ const cacheEnabled = config.cacheValues.cacheEnabled; // Variable to indicate wh /** * 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 @@ -124,6 +125,10 @@ const httpRequest = async ( } return sendStatusCode ? { ...response.data, statusCode: responseStatus } : response.data; } + else{ + logger.warn(`Error occurred while making request to ${getServiceName(_url)}: with error response ${JSON.stringify(response.data)}`); + return sendStatusCode ? { ...response.data, statusCode: responseStatus } : response.data; + } } catch (error: any) { const errorResponse = error?.response; logger.error( @@ -148,25 +153,50 @@ const httpRequest = async ( errorResponse?.data || { Errors: [{ code: error.message, description: error.stack }] } )}` ); - if (retry) { + if ( + retry || + (config.values.autoRetryIfHttpError && + config.values.autoRetryIfHttpError?.includes( + errorResponse?.data?.Errors?.[0]?.code + )) + ) { + logger.info( + `retrying the failed api call since retry is enabled or error is equal to configured ${config.values.autoRetryIfHttpError}` + ); attempt++; if (attempt >= maxAttempts) { if (dontThrowError) { - logger.warn(`Maximum retry attempts reached for httprequest with url ${_url}`); - return errorResponse?.data || { Errors: [{ code: error.message, description: error.stack }] }; + logger.warn( + `Maximum retry attempts reached for httprequest with url ${_url}` + ); + return ( + errorResponse?.data || { + Errors: [{ code: error.message, description: error.stack }], + } + ); } else { throwTheHttpError(errorResponse, error, _url); } } - logger.warn(`Waiting for 20 seconds before retrying httprequest with url ${_url}`); + logger.warn( + `Waiting for 20 seconds before retrying httprequest with url ${_url}` + ); await new Promise((resolve) => setTimeout(resolve, 20000)); } else if (dontThrowError) { logger.warn( - `Error occurred while making request to ${getServiceName(_url)}: returning error response ${JSON.stringify( - errorResponse?.data || { Errors: [{ code: error.message, description: error.stack }] } + `Error occurred while making request to ${getServiceName( + _url + )}: returning error response ${JSON.stringify( + errorResponse?.data || { + Errors: [{ code: error.message, description: error.stack }], + } )}` ); - return errorResponse?.data || { Errors: [{ code: error.message, description: error.stack }] }; + return ( + errorResponse?.data || { + Errors: [{ code: error.message, description: error.stack }], + } + ); } else { throwTheHttpError(errorResponse, error, _url); } 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..7e102feb6d8 --- /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?.boundariesCombined + } + }; + + 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/utils/transforms/localisationMessageConstructor.ts b/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts index a2528ce515d..64aa3cacef5 100644 --- a/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts +++ b/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts @@ -4,6 +4,7 @@ import { } from "../localisationUtils"; import Localisation from "../../controllers/localisationController/localisation.controller"; import { logger } from "../logger"; +import config from "../../config"; /** * Transforms boundary map into localisation messages and creates localisation entries. @@ -11,36 +12,114 @@ import { logger } from "../logger"; * @param hierarchyType - Type of hierarchy for the localisation module. * @param request - Request object containing necessary information. */ -export const transformAndCreateLocalisation = ( + +export const transformAndCreateLocalisation = async ( boundaryMap: any, request: any ) => { - const { tenantId, hierarchyType } = request?.body?.ResourceDetails || {}; + const CHUNK_SIZE = config.localisation.localizationChunkSizeForBoundaryCreation + + try { + const { tenantId, hierarchyType } = request?.body?.ResourceDetails || {}; - // Get localisation module name based on hierarchy type - const module = getLocalisationModuleName(hierarchyType); + // Get localisation module name based on hierarchy type + const module = getLocalisationModuleName(hierarchyType); - // Get locale from request object - const locale = getLocaleFromRequest(request); + // Get locale from request object + const locale = getLocaleFromRequest(request); - // Array to store localisation messages - const localisationMessages: any = []; + // 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, + // Iterate over boundary map to transform into localisation messages + boundaryMap.forEach((code: string, boundary: any) => { + if(boundary.value !== '' && boundary.value !== undefined){ + localisationMessages.push({ + code, + message: boundary.value, + module, + locale, + }); + } }); - }) + logger.info("Localisation message transformed successfully from the boundary map"); + + // Call the chunk upload function + await uploadInChunks(localisationMessages, CHUNK_SIZE, tenantId, request); + + logger.info("All chunks uploaded successfully"); + + } catch (error) { + logger.error("Error during transformation and localisation creation:", error); + throw error; // You can further handle this error (e.g., send failure response to client) + } +} + +const uploadInChunks = async (messages: any, chunkSize: any, tenantId: any, request: any) => { + // Check if messages is a valid array and chunkSize is a positive number + if (!Array.isArray(messages) || messages.length === 0) { + logger.error("Invalid or empty messages array provided"); + return; + } + if (typeof chunkSize !== 'number' || chunkSize <= 0) { + logger.error("Invalid chunkSize provided"); + return; + } + const MAX_RETRIES = 3; // Maximum number of retries for a chunk + // Break the messages array into chunks + for (let i = 0; i < messages.length; i += chunkSize) { + let retries = 0; + let success = false; + const chunk = messages.slice(i, i + chunkSize); + logger.info(`Total messages count ${messages?.length}`); + while (retries <= MAX_RETRIES) { + try { + logger.info(`Uploading chunk ${Math.floor(i / chunkSize) + 1}/${Math.ceil(messages.length / chunkSize)} of size ${chunkSize}`); + + // Check if tenantId and request are defined + if (!tenantId || !request) { + throw new Error("tenantId or request is not defined"); + } + + // Instantiate localisation controller + const localisation = Localisation.getInstance(); + + // Upload the current chunk + await localisation.createLocalisation(chunk, tenantId, request); + + // wait for 3 second + const waitTime = config.localisation.localizationWaitTimeInBoundaryCreation + logger.info(`Waiting for ${waitTime / 1000} seconds after each localisation chunk`); + await new Promise((resolve) => setTimeout(resolve, waitTime)); + await localisation.cacheBurst(); + + logger.info(`Successfully uploaded chunk ${Math.floor(i / chunkSize) + 1}`); + success = true; // Mark as successful + break; + } catch (error: any) { + retries += 1; + logger.info(`Retrying chunk ${Math.floor(i / chunkSize) + 1}, Attempt ${retries}`); + logger.error( + `Error uploading chunk ${Math.floor(i / chunkSize) + 1}, Attempt ${retries}: ${error.message}` + ); + + // If retries are exhausted, log failure and move on + if (retries > MAX_RETRIES) { + logger.error( + `Failed to upload chunk ${Math.floor(i / chunkSize) + 1} after ${MAX_RETRIES} retries` + ); + } + + // Optional: Add a delay between retries + await new Promise((resolve) => setTimeout(resolve, 1000)); + } + } + if (!success) { + logger.warn(`Skipping chunk ${Math.floor(i / chunkSize) + 1} after exhausting retries`); + } + } + logger.info("Finished processing all chunks"); +}; - 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 index e279306f7ce..c8cddff7a18 100644 --- a/health-services/project-factory/src/server/utils/transforms/projectTypeUtils.ts +++ b/health-services/project-factory/src/server/utils/transforms/projectTypeUtils.ts @@ -54,32 +54,40 @@ const defaultProjectType: any = { Convert campaign details to project details enriched with campaign information. */ export const projectTypeConversion = ( - projectType: any = {}, campaignObject: any = {} ) => { const deliveryRules = campaignObject.deliveryRules; - const resources = getUniqueArrayByProductVariantId(deliveryRules.flatMap((e: { products: any }) => - [...e.products].map((ele, ind) => ({ - isBaseUnitVariant: ind == 0, - productVariantId: ele.value, - })) - )); - const minAndMaxAge = getMinAndMaxAge(deliveryRules); - 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") { - newProjectType["cycles"] = transformData(deliveryRules); - } - logger.debug( - "transformed projectType : " + getFormattedStringForDebug(newProjectType) - ); - return newProjectType; + // const resources = getUniqueArrayByProductVariantId(deliveryRules.flatMap((e: { products: any }) => + // [...e.products].map((ele, ind) => ({ + // isBaseUnitVariant: ind == 0, + // productVariantId: ele.value, + // })) + // )); +// /* Temporay fix for project creation of LLIN since the structure of delivery rules is getting changed */ +// const resources = getUniqueArrayByProductVariantId(deliveryRules.flatMap((e:any) => +// [...e.deliveries].map((ele, ind) => ({ +// isBaseUnitVariant: ind == 0, +// productVariantId: ele.deliveryRules?.[0]?.products?.[0]?.value, +// })) +// )); +// const minAndMaxAge = getMinAndMaxAge(deliveryRules); +// 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") { +// newProjectType["cycles"] = transformData(deliveryRules); +// } +// logger.debug( +// "transformed projectType : " + getFormattedStringForDebug(newProjectType) +// ); + /* since the structure of delivery rules is getting changed so returning back the same delivery rules */ + + return deliveryRules?.[0] || defaultProjectType?.["LLIN-mz"]; }; /* Enrich project details from campaign details. @@ -94,10 +102,7 @@ export const enrichProjectDetailsFromCampaignDetails = ( logger.debug( "project type : " + getFormattedStringForDebug(projectTypeObject) ); - const defaultProject = - projectTypeObject || - defaultProjectType?.[projectType] || - defaultProjectType?.["MR-DN"]; + const defaultProject = projectTypeConversion( CampaignDetails); return [ { tenantId, @@ -106,11 +111,11 @@ export const enrichProjectDetailsFromCampaignDetails = ( endDate, projectSubType: projectType, department: defaultProject?.group, - description: defaultProject?.name, + description:`${defaultProject?.name}, disease ${defaultProject?.group} campaign created through Admin Console with Campaign Id as ${CampaignDetails?.campaignNumber}`, projectTypeId: defaultProject?.id, name: campaignName, additionalDetails: { - projectType: projectTypeConversion(defaultProject, CampaignDetails), + projectType: defaultProject, }, }, ]; @@ -118,7 +123,7 @@ export const enrichProjectDetailsFromCampaignDetails = ( /* construct max and min age */ -const getMinAndMaxAge = (deliveries = []) => { +export 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) @@ -281,7 +286,7 @@ const getRequiredCondition = (conditions: Condition[]): string => { }; // Transformation function -const transformData = (input: DeliveryItem[]): TransformedCycle[] => { +export const transformData = (input: DeliveryItem[]): TransformedCycle[] => { const groupedByCycle = input.reduce>((acc, item) => { const { cycleNumber, deliveryNumber, deliveryType, products, conditions,startDate,endDate } = item; diff --git a/health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts b/health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts index 783fb22edd8..7e5391847fb 100644 --- a/health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts +++ b/health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts @@ -39,6 +39,8 @@ export const campaignDetailsTransformer = (dbRows: any[] = []) => { status: row?.status, action: row?.action, campaignNumber: row?.campaignnumber, + isActive: row?.isactive, + parentId: row?.parentid, campaignName: row?.campaignname, projectType: row?.projecttype, hierarchyType: row?.hierarchytype, diff --git a/health-services/project-factory/src/server/validators/campaignValidators.ts b/health-services/project-factory/src/server/validators/campaignValidators.ts index cddd2c9958a..c166daddf89 100644 --- a/health-services/project-factory/src/server/validators/campaignValidators.ts +++ b/health-services/project-factory/src/server/validators/campaignValidators.ts @@ -2,11 +2,11 @@ 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"; -import { createBoundaryMap, generateProcessedFileAndPersist, getFinalValidHeadersForTargetSheetAsPerCampaignType, getLocalizedName } from "../utils/campaignUtils"; +import { createBoundaryMap, enrichInnerCampaignDetails, generateProcessedFileAndPersist, getFinalValidHeadersForTargetSheetAsPerCampaignType, getLocalizedName } from "../utils/campaignUtils"; import { validateBodyViaSchema, validateCampaignBodyViaSchema, validateHierarchyType } from "./genericValidator"; import { searchCriteriaSchema } from "../config/models/SearchCriteria"; import { searchCampaignDetailsSchema } from "../config/models/searchCampaignDetails"; @@ -20,8 +20,13 @@ 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"; +import { getBoundariesFromCampaignSearchResponse, validateBoundariesIfParentPresent } from "../utils/onGoingCampaignUpdateUtils"; +import { validateExtraBoundariesForMicroplan, validateFacilityBoundaryForLowestLevel, validateLatLongForMicroplanCampaigns, validatePhoneNumberSheetWise, validateTargetsForMicroplanCampaigns, validateUniqueSheetWise, validateUserForMicroplan } from "./microplanValidators"; +import { produceModifiedMessages } from "../kafka/Producer"; +import { planConfigSearch, planFacilitySearch } from "../utils/microplanUtils"; +import { getPvarIds } from "../utils/campaignMappingUtils"; +import { fetchProductVariants } from "../api/healthApis"; @@ -83,147 +88,9 @@ 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}` - ); - } -} - -// 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, 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!']}`); - } - - 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); -// 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!"]} 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!"]} 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!"]} 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!"]} 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!"]} 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!"]} 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]; -// await validateTargets(request, data, lowestLevelHierarchy, errors, localizationMap); -// } - - -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)); - const localizedTargetColumnNames = getLocalizedHeaders(columnsToValidate, localizationMap); +function validateTargetForNormalCampaigns(data: any, errors: any, localizedTargetColumnNames: any, localizationMap?: { [key: string]: string }) { for (const key in data) { - if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { + 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) => { @@ -265,8 +132,34 @@ async function validateTargets(request: any, data: any[], errors: any[], localiz } } -async function validateUnique(schema: any, data: any[], request: any) { - const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId); + +async function validateTargets(request: any, data: any[], errors: any[], localizationMap?: any) { + 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); + if (request?.body?.ResourceDetails?.additionalDetails?.source === "microplan") { + validateTargetsForMicroplanCampaigns(data, errors, localizedTargetColumnNames, localizationMap); + validateLatLongForMicroplanCampaigns(data, errors, localizationMap); + } + else { + validateTargetForNormalCampaigns(data, errors, localizedTargetColumnNames, localizationMap); + } +} + +function validateUnique(schema: any, data: any[], request: any, localizationMap: any) { if (schema?.unique) { const uniqueElements = schema.unique; const errors = []; @@ -277,7 +170,7 @@ async function validateUnique(schema: any, data: any[], request: any) { // 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 localizedUniqueIdentifierColumnName = getLocalizedName(uniqueIdentifierColumnName, localizationMap); const value = item[element]; const rowNum = item['!row#number!']; if (!localizedUniqueIdentifierColumnName || !item[localizedUniqueIdentifierColumnName]) { @@ -332,6 +225,7 @@ function validatePhoneNumber(datas: any[], localizationMap: any) { } } + async function changeSchemaErrorMessage(schema: any, localizationMap?: any) { if (schema?.errorMessage) { for (const key in schema.errorMessage) { @@ -343,9 +237,54 @@ async function changeSchemaErrorMessage(schema: any, localizationMap?: any) { return schema; // Return unmodified schema if no error message } +function validateData(data: any[], validationErrors: any[], activeColumnName: any, uniqueIdentifierColumnName: any, validate: any) { + data.forEach((item: any) => { + if (activeColumnName) { + if (!item?.[activeColumnName]) { + validationErrors.push({ index: item?.["!row#number!"], errors: [{ instancePath: `${activeColumnName}`, message: `should not be empty` }] }); + } + else if (item?.[activeColumnName] != "Active" && item?.[activeColumnName] != "Inactive") { + validationErrors.push({ index: item?.["!row#number!"], errors: [{ instancePath: `${activeColumnName}`, message: `should be equal to one of the allowed values. Allowed values are Active, Inactive` }] }); + } + } + const active = activeColumnName ? item[activeColumnName] : "Active"; + if (active == "Active" || !item?.[uniqueIdentifierColumnName]) { + const validationResult = validate(item); + if (!validationResult) { + validationErrors.push({ index: item?.["!row#number!"], errors: validate.errors }); + } + } + }); +} + +function enrichRowMappingViaValidation(validationErrors: any[], rowMapping: any, localizationMap?: any) { + if (validationErrors.length > 0) { + const errorMessage = validationErrors.map(({ index, message, errors }) => { + const formattedErrors = errors ? errors.map((error: any) => { + let instancePath = error.instancePath || ''; // Assign an empty string if dataPath is not available + if (instancePath.startsWith('/')) { + instancePath = instancePath.slice(1); + } + if (error.keyword === 'required') { + const missingProperty = error.params?.missingProperty || ''; + return `Data at row ${index} in column '${missingProperty}' should not be empty`; + } + let formattedError = `in column '${instancePath}' ${getLocalizedName(error.message, localizationMap)}`; + if (error.keyword === 'enum' && error.params && error.params.allowedValues) { + formattedError += `. Allowed values are: ${error.params.allowedValues.join(', ')}`; + } + return `Data at row ${index} ${formattedError}` + }).join(' ; ') : message; + return formattedErrors; + }).join(' ; '); + throwError("COMMON", 400, "VALIDATION_ERROR", errorMessage); + } else { + logger.info("All Data rows are valid."); + } +} -async function validateViaSchema(data: any, schema: any, request: any, localizationMap?: any) { +export async function validateViaSchema(data: any, schema: any, request: any, localizationMap?: any) { if (schema) { const newSchema: any = await changeSchemaErrorMessage(schema, localizationMap) const ajv = new Ajv({ allErrors: true, strict: false }); // enable allErrors to get all validation errors @@ -357,70 +296,124 @@ async function validateViaSchema(data: any, schema: any, request: any, localizat if (request?.body?.ResourceDetails?.type == "user") { validatePhoneNumber(data, localizationMap); } - if (data?.length > 0) { - data.forEach((item: any) => { - if (activeColumnName) { - if (!item?.[activeColumnName]) { - validationErrors.push({ index: item?.["!row#number!"], errors: [{ instancePath: `${activeColumnName}`, message: `should not be empty` }] }); - } - else if (item?.[activeColumnName] != "Active" && item?.[activeColumnName] != "Inactive") { - validationErrors.push({ index: item?.["!row#number!"], errors: [{ instancePath: `${activeColumnName}`, message: `should be equal to one of the allowed values. Allowed values are Active, Inactive` }] }); - } - } - const active = activeColumnName ? item[activeColumnName] : "Active"; - if (active == "Active" || !item?.[uniqueIdentifierColumnName]) { - const validationResult = validate(item); - if (!validationResult) { - validationErrors.push({ index: item?.["!row#number!"], errors: validate.errors }); + if (data?.length > 0 && request?.body?.ResourceDetails?.additionalDetails?.source != "microplan") { + if (!request?.body?.parentCampaignObject && data[0]?.[getLocalizedName("HCM_ADMIN_CONSOLE_BOUNDARY_CODE_OLD", localizationMap)]) { + throwError("COMMON", 400, "VALIDATION_ERROR", `${request?.body?.ResourceDetails?.type} template downloaded from update campaign flow has been uploaded in create campaign flow`); + } + validateData(data, validationErrors, activeColumnName, uniqueIdentifierColumnName, validate); + validateUnique(newSchema, data, request, localizationMap); + enrichRowMappingViaValidation(validationErrors, request?.body?.rowMapping, localizationMap); + } + if (data?.length == 0) { + throwError("FILE", 400, "INVALID_FILE_ERROR", "Data rows cannot be empty"); + } + } else { + logger.info("Skipping schema validation"); + } +} + +function validateDataSheetWise(data: any, validate: any, validationErrors: any[], uniqueIdentifierColumnName: any, activeColumnName: any) { + data.forEach((item: any) => { + const validationResult = validate(item); + if (!validationResult) { + validationErrors.push({ index: item?.["!row#number!"], errors: validate.errors }); + } + }); +} + +function enrichRowMappingViaValidationSheetwise(rowMapping: any, validationErrors: any[], localizationMap: any) { + if (validationErrors.length > 0) { + validationErrors.map(({ index, message, errors }) => { + if (errors) { + errors.map((error: any) => { + let instancePath = error.instancePath || ''; // Assign an empty string if instancePath is not available + if (instancePath.startsWith('/')) { + instancePath = instancePath.slice(1); } - } - }); - await validateUnique(newSchema, data, request); - if (validationErrors.length > 0) { - const errorMessage = validationErrors.map(({ index, message, errors }) => { - const formattedErrors = errors ? errors.map((error: any) => { - let instancePath = error.instancePath || ''; // Assign an empty string if dataPath is not available - if (instancePath.startsWith('/')) { - instancePath = instancePath.slice(1); - } - if (error.keyword === 'required') { - const missingProperty = error.params?.missingProperty || ''; - return `Data at row ${index} in column '${missingProperty}' should not be empty`; + + // Handle 'required' keyword errors + if (error.keyword === 'required') { + const missingProperty = error.params?.missingProperty || ''; + if (!rowMapping[index]) { + rowMapping[index] = []; } - let formattedError = `in column '${instancePath}' ${getLocalizedName(error.message, localizationMap)}`; + rowMapping[index].push(`Data in column '${missingProperty}' should not be empty`); + } + else { + // Format the general error message + let formattedError = `Data in column '${instancePath}' ${getLocalizedName(error.message, localizationMap)}`; + + // Handle 'enum' keyword errors if (error.keyword === 'enum' && error.params && error.params.allowedValues) { formattedError += `. Allowed values are: ${error.params.allowedValues.join(', ')}`; } - return `Data at row ${index} ${formattedError}` - }).join(' ; ') : message; - return formattedErrors; - }).join(' ; '); - throwError("COMMON", 400, "VALIDATION_ERROR", errorMessage); - } else { - logger.info("All Data rows are valid."); + else if (error.keyword === 'pattern') { + formattedError = `Data in column '${instancePath}' is invalid` + } + + // Ensure rowMapping[index] exists + if (!rowMapping[index]) { + rowMapping[index] = []; + } + rowMapping[index].push(`${formattedError}`); + } + }) + } + }); + } + else { + logger.info("All Data rows are valid."); + } +} + +export async function validateViaSchemaSheetWise(dataFromExcel: any, schema: any, request: any, localizationMap?: any) { + const errorMap: any = {}; + for (const sheetName of Object.keys(dataFromExcel)) { + const data = dataFromExcel[sheetName]; + const rowMapping: any = {}; + if (schema) { + const newSchema: any = await changeSchemaErrorMessage(schema, localizationMap) + const ajv = new Ajv({ allErrors: true, strict: false }); // enable allErrors to get all validation errors + addAjvErrors(ajv); + const validate = ajv.compile(newSchema); + const validationErrors: any[] = []; + const uniqueIdentifierColumnName = getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName, localizationMap); + const activeColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName, localizationMap) : null; + if (request?.body?.ResourceDetails?.type == "user" && request?.body?.ResourceDetails?.additionalDetails?.source == "microplan") { + validateUserForMicroplan(data, sheetName, request, errorMap, newSchema, rowMapping, localizationMap); + } + else { + if (request?.body?.ResourceDetails?.type == "user") { + validatePhoneNumberSheetWise(data, localizationMap, rowMapping); + } + if (data?.length > 0) { + validateDataSheetWise(data, validate, validationErrors, uniqueIdentifierColumnName, activeColumnName); + validateUniqueSheetWise(newSchema, data, request, rowMapping, localizationMap); + enrichRowMappingViaValidationSheetwise(rowMapping, validationErrors, localizationMap); + } else { + errorMap[sheetName] = { 2: ["Data rows cannot be empty"] }; + } } } else { - throwError("FILE", 400, "INVALID_FILE_ERROR", "Data rows cannot be empty"); + logger.info("Skipping schema validation"); + } + if (Object.keys(rowMapping).length > 0) { + errorMap[sheetName] = rowMapping; } - } else { - logger.info("Skipping schema validation"); } + return errorMap; } 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 +433,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); @@ -488,7 +481,7 @@ function validateStorageCapacity(obj: any, index: any) { async function validateCampaignId(request: any) { - const { campaignId, tenantId, type } = request?.body?.ResourceDetails; + const { campaignId, tenantId, type, additionalDetails } = request?.body?.ResourceDetails; if (type == "boundary") { return; } @@ -496,28 +489,30 @@ async function validateCampaignId(request: any) { throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignId is missing"); } else { - const searchBody = { - CampaignDetails: { + // const searchBody = { + const CampaignDetails= { ids: [campaignId], tenantId: tenantId } - } - const req: any = replicateRequest(request, searchBody); - const response = await searchProjectTypeCampaignService(req); + // const req: any = replicateRequest(request, searchBody); + const response = await searchProjectTypeCampaignService(CampaignDetails); if (response?.CampaignDetails?.[0]) { - const campaign = response?.CampaignDetails?.[0] - if (!campaign?.boundaries) { + const boundaries = await getBoundariesFromCampaignSearchResponse(request, response?.CampaignDetails?.[0]); + if (!boundaries) { throwError("COMMON", 400, "VALIDATION_ERROR", "Campaign with given campaignId does not have any boundaries"); } - if (!Array.isArray(campaign?.boundaries)) { + if (!Array.isArray(boundaries)) { throwError("COMMON", 400, "VALIDATION_ERROR", "Boundaries of campaign with given campaignId is not an array"); } - if (campaign?.boundaries?.length === 0) { + if (boundaries?.length === 0) { throwError("COMMON", 400, "VALIDATION_ERROR", "Campaign with given campaignId does not have any boundaries"); } + request.body.campaignBoundaries = boundaries } else { - throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND", "Campaign not found while validating campaignId"); + if (!(additionalDetails?.source == "microplan" && type == "user")) { + throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND", "Campaign not found while validating campaignId"); + } } } } @@ -528,9 +523,12 @@ async function validateCreateRequest(request: any, localizationMap?: any) { throwError("COMMON", 400, "VALIDATION_ERROR", "ResourceDetails is missing or empty or null"); } else { + const type = request?.body?.ResourceDetails?.type; // validate create request body validateBodyViaSchema(createRequestSchema, request.body.ResourceDetails); - await validateCampaignId(request); + if (type !== "boundaryManagement" && request?.body?.ResourceDetails.campaignId !== "default") { + 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"); @@ -540,13 +538,6 @@ async function validateCreateRequest(request: any, localizationMap?: any) { if (request.body.ResourceDetails.type == 'boundary') { await validateBoundarySheetData(request, fileUrl, localizationMap); } - // if (request?.body?.ResourceDetails?.type == 'boundaryWithTarget') { - // 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); - // logger.info("finalValidHeadersForTargetSheetAsPerCampaignType :" + JSON.stringify(finalValidHeadersForTargetSheetAsPerCampaignType)); - // validateTabsWithTargetInTargetSheet(targetWorkbook, finalValidHeadersForTargetSheetAsPerCampaignType); - // } } } @@ -554,9 +545,10 @@ function validateHeadersOfTabsWithTargetInTargetSheet(targetWorkbook: any, expec targetWorkbook.eachSheet((worksheet: any, sheetId: any) => { if (sheetId > 2) { // Starting from the second sheet // Convert the sheet to an array of headers - const headersToValidate = worksheet.getRow(1).values + let headersToValidate = worksheet.getRow(1).values .filter((header: any) => header !== undefined && header !== null && header.toString().trim() !== '') .map((header: any) => header.toString().trim()); + headersToValidate = headersToValidate.filter((header: string) => header !== '#status#' && header !== '#errorDetails#'); if (!_.isEqual(expectedHeadersForTargetSheet, headersToValidate)) { throwError("COMMON", 400, "VALIDATION_ERROR", `Headers not according to the template in Target sheet ${worksheet.name}`); } @@ -668,6 +660,7 @@ async function validateCampaignBoundary(boundaries: any[], hierarchyType: any, t } } + async function validateProjectCampaignBoundaries(boundaries: any[], hierarchyType: any, tenantId: any, request: any): Promise { if (!request?.body?.CampaignDetails?.projectId) { if (boundaries) { @@ -705,14 +698,18 @@ async function validateBoundariesForTabs(CampaignDetails: any, resource: any, re // 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); - + var boundaryColumn: any; + if (resource?.additionalDetails?.source == 'microplan') { + boundaryColumn = getLocalizedName(createAndSearch?.[`${resource.type}Microplan`]?.boundaryValidation?.column, localizationMap); + } + else { + boundaryColumn = getLocalizedName(createAndSearch?.[resource.type]?.boundaryValidation?.column, localizationMap); + } // Initialize resource boundary codes as a set for uniqueness 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,8 +727,9 @@ 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 }) } + validateFacilityBoundaryForLowestLevel(request, boundaries, rowData, errors, localizationMap); } if (errors?.length > 0) { request.body.ResourceDetails.status = resourceDataStatuses.invalid @@ -810,14 +808,16 @@ async function validateProjectCampaignResources(resources: any, request: any) { missingTypes.push(type); } } - - if (missingTypes.length > 0) { - const missingTypesMessage = `Missing resources of types: ${missingTypes.join(', ')}`; - throwError("COMMON", 400, "VALIDATION_ERROR", missingTypesMessage); + if ((!request?.body?.parentCampaign) || (request?.body?.parentCampaign && request?.body?.CampaignDetails?.boundaries && request.body.CampaignDetails.boundaries.length > 0)) { + 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); + logger.info(`skipResourceCheckValidationBeforeCreateForLocalTesting flag is ${config.values.skipResourceCheckValidationBeforeCreateForLocalTesting }`); + !config.values.skipResourceCheckValidationBeforeCreateForLocalTesting && await validateResources(request.body.CampaignDetails.resources, request); } } @@ -826,33 +826,46 @@ async function validateProjectCampaignResources(resources: any, request: any) { 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, action } = CampaignDetails; - if (action != "changeDates") { - 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"); +} + +async function validateParent(request: any, actionInUrl: any) { + if (request?.body?.CampaignDetails?.parentId) { + const tenantId = request.body.CampaignDetails?.tenantId + const CampaignDetails = { + tenantId: tenantId, + ids: [request.body.CampaignDetails?.parentId] } - const today: any = Date.now(); - if (startDate <= today) { - throwError("COMMON", 400, "VALIDATION_ERROR", "startDate cannot be today or past date"); + const parentSearchResponse: any = await searchProjectTypeCampaignService(CampaignDetails) + if (Array.isArray(parentSearchResponse?.CampaignDetails)) { + if (actionInUrl == "create") { + if (parentSearchResponse?.CampaignDetails?.length > 0 && parentSearchResponse?.CampaignDetails?.[0]?.status == "created" && + parentSearchResponse?.CampaignDetails?.[0]?.isActive) { + request.body.parentCampaign = parentSearchResponse?.CampaignDetails[0] + } + else { + throwError("CAMPAIGN", 400, "PARENT_CAMPAIGN_ERROR", "Parent Campaign can't be inactive when creating child campaign"); + } + } + else { + if (parentSearchResponse?.CampaignDetails?.length > 0 && parentSearchResponse?.CampaignDetails?.[0]?.status == "created" && + !parentSearchResponse?.CampaignDetails?.[0]?.isActive) { + request.body.parentCampaign = parentSearchResponse?.CampaignDetails[0] + } + else { + throwError("CAMPAIGN", 400, "PARENT_CAMPAIGN_ERROR", "Parent Campaign can't be active when updating child campaign"); + } + + } } } } async function validateCampaignName(request: any, actionInUrl: any) { - const CampaignDetails = request.body.CampaignDetails; - const { campaignName, tenantId } = CampaignDetails; + const { campaignName, tenantId } = request.body.CampaignDetails; if (!campaignName) { throwError("COMMON", 400, "VALIDATION_ERROR", "campaignName is required"); } @@ -860,25 +873,38 @@ async function validateCampaignName(request: any, actionInUrl: any) { throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is required"); } if (campaignName.length >= 2) { - const searchBody = { - RequestInfo: request.body.RequestInfo, - CampaignDetails: { + // const searchBody = { + // RequestInfo: request.body.RequestInfo, + const CampaignDetails = { tenantId: tenantId, - campaignName: campaignName + campaignName: campaignName, + status: [campaignStatuses.drafted, campaignStatuses.started, campaignStatuses.inprogress], + } + // } + if (request.body?.parentCampaign) { + if (request?.body?.CampaignDetails?.campaignName != request?.body?.parentCampaign?.campaignName) { + throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_NOT_MATCHING_PARENT_ERROR", "Campaign name should be same as that of parent"); } } - const req: any = replicateRequest(request, searchBody) - const searchResponse: any = await searchProjectTypeCampaignService(req) + // const req: any = replicateRequest(request, searchBody) + const searchResponse: any = await searchProjectTypeCampaignService(CampaignDetails) 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"); + const matchingCampaigns: any[] = allCampaigns.filter((campaign: any) => campaign?.campaignName === campaignName); + for (const campaignWithMatchingName of matchingCampaigns) { + if (campaignWithMatchingName && actionInUrl == "create") { + if (!request.body.CampaignDetails?.parentId) { + throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_ERROR"); + } + else if (campaignWithMatchingName?.id != request.body.CampaignDetails?.parentId) { + throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_ERROR"); + } + } + else if (campaignWithMatchingName && actionInUrl == "update" && campaignWithMatchingName?.id != request.body.CampaignDetails?.id) { + throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_ERROR"); + } } } } @@ -893,15 +919,15 @@ async function validateById(request: any) { if (!id) { throwError("COMMON", 400, "VALIDATION_ERROR", "id is required"); } - const searchBody = { - RequestInfo: request.body.RequestInfo, - CampaignDetails: { + // const searchBody = { + // RequestInfo: request.body.RequestInfo, + const CampaignDetails ={ tenantId: tenantId, ids: [id] } - } - const req: any = replicateRequest(request, searchBody) - const searchResponse: any = await searchProjectTypeCampaignService(req) + // } + // const req: any = replicateRequest(request, searchBody) + const searchResponse: any = await searchProjectTypeCampaignService(CampaignDetails) if (Array.isArray(searchResponse?.CampaignDetails)) { if (searchResponse?.CampaignDetails?.length > 0) { logger.debug(`CampaignDetails : ${getFormattedStringForDebug(searchResponse?.CampaignDetails)}`); @@ -944,7 +970,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.mdmsV2 + config?.paths?.mdms_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)) { @@ -994,29 +1020,49 @@ async function validateChangeDatesRequest(request: any) { } async function validateCampaignBody(request: any, CampaignDetails: any, actionInUrl: any) { - const { hierarchyType, action, tenantId, boundaries, resources, projectType } = CampaignDetails; + const { hierarchyType, action, tenantId, resources, projectType } = CampaignDetails; if (action == "changeDates") { await validateChangeDatesRequest(request); } else if (action == "create") { validateProjectCampaignMissingFields(CampaignDetails); + await validateParent(request, actionInUrl) + validateBoundariesIfParentPresent(request); + validateProjectDatesForCampaign(request, 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 validateProjectCampaignBoundaries(request?.body?.boundariesCombined, hierarchyType, tenantId, request); await validateProjectCampaignResources(resources, request); + await validateProductVariant(request); } else { validateDraftProjectCampaignMissingFields(CampaignDetails); + await validateParent(request, actionInUrl); + validateBoundariesIfParentPresent(request); + validateProjectDatesForCampaign(request, CampaignDetails); await validateCampaignName(request, actionInUrl); await validateHierarchyType(request, hierarchyType, tenantId); await validateProjectType(request, projectType, tenantId); } } +function validateProjectDatesForCampaign(request: any, CampaignDetails: any) { + if (!request?.body?.parentCampaign) { + 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 validateProjectCampaignRequest(request: any, actionInUrl: any) { const CampaignDetails = request.body.CampaignDetails; const { id, action } = CampaignDetails; @@ -1031,11 +1077,20 @@ async function validateProjectCampaignRequest(request: any, actionInUrl: any) { if (!action) { throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails.action is required and must be either 'create' or 'draft'") } - if (!(action == "create" || action == "draft" || action == "changeDates")) { - throwError("COMMON", 400, "VALIDATION_ERROR", "action can only be create, draft or changeDates"); + if (!(action == "create" || action == "draft" || action == "changeDates" || action == "retry")) { + throwError("COMMON", 400, "VALIDATION_ERROR", "action can only be create, draft, retry or changeDates"); + } + if (actionInUrl == "retry") { + await validateForRetry(request); } if (actionInUrl == "update") { await validateById(request); + await validateIsActive(request); + } + if (actionInUrl == "create") { + if (!request?.body?.CampaignDetails?.isActive) { + request.body.CampaignDetails.isActive = true; + } } if (action == "changeDates" && actionInUrl == "create") { throwError("COMMON", 400, "VALIDATION_ERROR", "changeDates is not allowed during create"); @@ -1043,6 +1098,109 @@ async function validateProjectCampaignRequest(request: any, actionInUrl: any) { await validateCampaignBody(request, CampaignDetails, actionInUrl); } +async function validateForRetry(request: any) { + if (!request.body || !request.body.CampaignDetails) { + throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails are missing in the request body"); + } + const { id, tenantId } = request.body.CampaignDetails; + if (!id) { + throwError("COMMON", 400, "VALIDATION_ERROR", "id is required"); + } + if (!tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is required"); + } + // const searchBody = { + // RequestInfo: request.body.RequestInfo, + const CampaignDetails= { + tenantId: tenantId, + ids: [id] + } + // } + // const req: any = replicateRequest(request, searchBody) + const searchResponse: any = await searchProjectTypeCampaignService(CampaignDetails) + if (Array.isArray(searchResponse?.CampaignDetails)) { + if (searchResponse?.CampaignDetails?.length > 0) { + logger.debug(`CampaignDetails : ${getFormattedStringForDebug(searchResponse?.CampaignDetails)}`); + request.body.ExistingCampaignDetails = searchResponse?.CampaignDetails[0]; + if (request.body.ExistingCampaignDetails?.status != campaignStatuses?.failed) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Campaign can only be retried in failed state.`); + } + request.body.CampaignDetails.status = campaignStatuses?.drafted; + var updatedInnerCampaignDetails = {} + enrichInnerCampaignDetails(request, updatedInnerCampaignDetails) + request.body.CampaignDetails.campaignDetails = updatedInnerCampaignDetails; + const producerMessage: any = { + CampaignDetails: request?.body?.CampaignDetails + } + await produceModifiedMessages(producerMessage, config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC); + + if (!request.body.CampaignDetails.additionalDetails.retryCycle) { + // If not present, initialize it as an empty array + request.body.CampaignDetails.additionalDetails.retryCycle = []; + } + + // Step 2: Push new data to the `retryCycle` array + request.body.CampaignDetails.additionalDetails.retryCycle.push({ + error: request.body.CampaignDetails.additionalDetails.error, + retriedAt: Date.now(), + failedAt: request.body.CampaignDetails.auditDetails.lastModifiedTime + }); + } + else { + throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND"); + } + } + else { + throwError("CAMPAIGN", 500, "CAMPAIGN_SEARCH_ERROR"); + } +} + +async function validateProductVariant(request: any) { + const deliveryRules = request?.body?.CampaignDetails?.deliveryRules; + + if (!Array.isArray(deliveryRules)) { + throwError("COMMON", 400, "VALIDATION_ERROR", "deliveryRules must be an array"); + } + + deliveryRules.forEach((rule: any, index: number) => { + const productVariants = rule?.resources; + if (!Array.isArray(productVariants) || productVariants.length === 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", `deliveryRules[${index}].resources must be a non-empty array`); + } + }); + const pvarIds= getPvarIds(request?.body); + await validatePvarIds(pvarIds as string[]); + logger.info("Validated product variants successfully"); +} + +async function validatePvarIds(pvarIds: string[]) { + // Validate that pvarIds is not null, undefined, or empty, and that no element is null or undefined + if (!pvarIds?.length || pvarIds.some((id:any) => !id)) { + throwError("COMMON", 400, "VALIDATION_ERROR", "productVariantId is required in every delivery rule's resources"); + } + + // Fetch product variants using the fetchProductVariants function + const allProductVariants = await fetchProductVariants(pvarIds); + + // Extract the ids of the fetched product variants + const fetchedIds = new Set(allProductVariants.map((pvar: any) => pvar?.id)); + + // Identify missing or invalid product variants + const missingPvarIds = pvarIds.filter((id: any) => !fetchedIds.has(id)); + + if (missingPvarIds.length) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Invalid product variant ${missingPvarIds.length === 1 ? 'id' : 'ids'}: ${missingPvarIds.join(", ")}`); + } +} + + +async function validateIsActive(request: any) { + if (!request?.body?.CampaignDetails.isActive) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Can't update isActive") + } +} + + async function validateSearchProjectCampaignRequest(request: any) { const CampaignDetails = request.body.CampaignDetails; if (!CampaignDetails) { @@ -1159,9 +1317,10 @@ 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); + await validateExtraBoundariesForMicroplan(request, dataFromSheet, 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,15 +1329,18 @@ 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')) { throwError("COMMON", 400, "VALIDATION_ERROR", `Invalid column has some random data in Target Sheet ${key} at row number ${boundaryRow['!row#number!']}`); } + if (!request?.body?.parentCampaignObject && columns.endsWith('(OLD)')) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Target template downloaded from update campaign flow has been uploaded in create campaign flow") + } } if (!boundaryRow[root]) { - throwError("COMMON", 400, "VALIDATION_ERROR", ` ${root} column is empty in Target Sheet ${key} at row number ${boundaryRow['!row#number!']}`); + throwError("COMMON", 400, "VALIDATION_ERROR", ` ${root} column is empty in Target Sheet ${key} at row number ${boundaryRow['!row#number!']}. Please upload from downloaded template only.`); } } } @@ -1187,19 +1349,18 @@ 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 `) + throwError("COMMON", 400, "VALIDATION_ERROR", `${differentTabsBasedOnLevel} tabs uploaded by user is either less or more than the ${differentTabsBasedOnLevel} in the boundary system. Please upload from downloaded template only.`); } else { for (let index = tabsIndex; index < tabsFromTargetSheet.length; index++) { const tab = tabsFromTargetSheet[index]; // Get the current tab @@ -1207,9 +1368,134 @@ function validateAllDistrictTabsPresentOrNot(dataFromSheet: any, localizationMap throwError("COMMON", 400, "VALIDATION_ERROR", `${differentTabsBasedOnLevel} tab ${tab} not present in the Target Sheet Uploaded`); } } + const MissingDistricts: any = []; + const campaignBoundaries = request?.body?.campaignBoundaries; + if (campaignBoundaries && campaignBoundaries?.length > 0) { + const districtsLocalised = campaignBoundaries + .filter((data: any) => getLocalizedName(`${request?.body?.ResourceDetails?.hierarchyType}_${data.type.toUpperCase()}`, localizationMap).toLocaleLowerCase() == differentTabsBasedOnLevel.toLowerCase()) + .map((data: any) => getLocalizedName(data?.code, localizationMap)) || []; + + tabsOfDistrict.forEach((tab: any) => { + if (!districtsLocalised.includes(tab)) { + MissingDistricts.push(tab); + } + }); + } + + if (MissingDistricts.length > 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Districts ${MissingDistricts.join(', ')} 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"); + } +} + +async function validateMicroplanRequest(request: any) { + const { tenantId, campaignId, planConfigurationId } = request.body.MicroplanDetails; + if (!tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is required"); + } + if (!campaignId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "campignId is required"); + } + if (!planConfigurationId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "planConfigurationId is required"); + } + logger.info("All required fields are present"); + + await validateCampaignFromId(request); + await validatePlanFacility(request); +} + +async function validatePlanFacility(request: any) { + const planConfigSearchResponse = await planConfigSearch(request); + const planFacilitySearchResponse = await planFacilitySearch(request); + + if (planFacilitySearchResponse.PlanFacility.length === 0) { + throwError("COMMAN", 400, "Plan facilities not found"); + } + request.body.PlanFacility = planFacilitySearchResponse.PlanFacility; + request.body.planConfig = planConfigSearchResponse.PlanConfiguration[0]; +} + +async function validateCampaignFromId(request: any) { + const { tenantId, campaignId } = request.body.MicroplanDetails; + + // const searchBody = { + // RequestInfo: request.body.RequestInfo, + const campaignDetails = { + tenantId: tenantId, + ids: [campaignId] + } + // } + + // const req: any = replicateRequest(request, searchBody) + const searchResponse: any = await searchProjectTypeCampaignService(campaignDetails); + + if (searchResponse?.CampaignDetails?.length == 0) { + throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND"); } + logger.info("Campaign Found"); + request.body.CampaignDetails = searchResponse?.CampaignDetails[0]; +} + + +function validateBoundarySheetDataInCreateFlow(boundarySheetData: any, localizedHeadersOfBoundarySheet: any) { + const firstColumnValues = new Set(); + const firstColumn = localizedHeadersOfBoundarySheet[0]; + + boundarySheetData.forEach((obj: any, index: number) => { + let firstEmptyFound = false; + // Collect value from the first column + if (obj[firstColumn]) { + firstColumnValues.add(obj[firstColumn]); + } + if (firstColumnValues.size > 1) { + throwError("BOUNDARY", 400, "BOUNDARY_SHEET_FIRST_COLUMN_INVALID_ERROR", + `Data is invalid: The "${firstColumn}" column must contain only one unique value across all rows.`); + } + + for (const header of localizedHeadersOfBoundarySheet) { + const value = obj[header]; + + if (!value) { + // Mark that an empty value has been found for the first time + firstEmptyFound = true; + } else if (firstEmptyFound) { + // If a non-empty value is found after an empty value in the expected order, throw an error + throwError("BOUNDARY", 400, "BOUNDARY_SHEET_UPLOADED_INVALID_ERROR", + `Data is invalid in object at index ${index + 2}: Non-empty value for key "${header}" found after an empty value in the left.`); + } + } + }); +} + +export function validateEmptyActive(data: any, type: string, localizationMap?: { [key: string]: string }) { + let isActiveRowsZero = true; + const activeColumnName = createAndSearch?.[type]?.activeColumnName ? getLocalizedName(createAndSearch?.[type]?.activeColumnName, localizationMap) : null; + if(Array.isArray(data)){ + data.forEach((item: any) => { + const active = activeColumnName ? item[activeColumnName] : "Active"; + if (active == "Active") { + isActiveRowsZero = false; + return; + } + }); + } + else{ + // Data is not coming from a single sheet so no require for this active check + isActiveRowsZero = false; + } + if(isActiveRowsZero){ + throwError("COMMON", 400, "VALIDATION_ERROR", "At least one active row is required"); + } } @@ -1227,5 +1513,10 @@ export { validateDownloadRequest, validateTargetSheetData, immediateValidationForTargetSheet, - validateBoundaryOfResouces + validateBoundaryOfResouces, + validateSearchProcessTracksRequest, + validateParent, + validateForRetry, + validateBoundarySheetDataInCreateFlow, + validateMicroplanRequest } diff --git a/health-services/project-factory/src/server/validators/genericValidator.ts b/health-services/project-factory/src/server/validators/genericValidator.ts index 426f1de67e7..5c8ed266a53 100644 --- a/health-services/project-factory/src/server/validators/genericValidator.ts +++ b/health-services/project-factory/src/server/validators/genericValidator.ts @@ -2,11 +2,14 @@ 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"; +import { persistTrack } from "../utils/processTrackUtils"; +import { processTrackTypes, processTrackStatuses, campaignStatuses } from "../config/constants"; +import { validateMappingId } from "../utils/campaignMappingUtils"; +import { searchBoundaryRelationshipDefinition } from "../api/coreApis"; +import { BoundaryModels } from "../models"; // 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 @@ -164,18 +202,18 @@ function validatedProjectResponseAndUpdateId(projectResponse: any, projectBody: // 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 BoundaryTypeHierarchySearchCriteria: BoundaryModels.BoundaryHierarchyDefinitionSearchCriteria={ + BoundaryTypeHierarchySearchCriteria:{ + tenantId, + hierarchyType } - } - const response = await httpRequest(config.host.boundaryHost + config.paths.boundaryHierarchy, searchBody); + }; + const response:BoundaryModels.BoundaryHierarchyDefinitionResponse =await searchBoundaryRelationshipDefinition(BoundaryTypeHierarchySearchCriteria); + if (response?.BoundaryHierarchy && Array.isArray(response?.BoundaryHierarchy) && response?.BoundaryHierarchy?.length > 0) { logger.info(`hierarchyType : ${hierarchyType} :: got validated`); + request.body.hierarchyType = response?.BoundaryHierarchy?.[0]; } else { throwError(`CAMPAIGN`, 400, "VALIDATION_ERROR", `hierarchyType ${hierarchyType} not found`); @@ -220,4 +258,4 @@ export { validateGenerateRequest, validateHierarchyType, validateCampaignBodyViaSchema -}; \ No newline at end of file +}; diff --git a/health-services/project-factory/src/server/validators/microplanValidators.ts b/health-services/project-factory/src/server/validators/microplanValidators.ts new file mode 100644 index 00000000000..4bc9f35ebaf --- /dev/null +++ b/health-services/project-factory/src/server/validators/microplanValidators.ts @@ -0,0 +1,323 @@ +import { getBoundaryColumnName, getBoundaryTabName } from "../utils/boundaryUtils"; +import createAndSearch from "../config/createAndSearch"; +import { getLocalizedName } from "../utils/campaignUtils"; +import { resourceDataStatuses } from "../config/constants"; +import config from "../config"; +import { isMicroplanRequest } from "../utils/microplanUtils"; +import { throwError } from "../utils/genericUtils"; + +export function validatePhoneNumberSheetWise(datas: any[], localizationMap: any, rowMapping: any) { + for (const data of datas) { + const phoneColumn = getLocalizedName("HCM_ADMIN_CONSOLE_USER_PHONE_NUMBER_MICROPLAN", localizationMap); + if (data[phoneColumn]) { + let phoneNumber = data[phoneColumn].toString(); + + // Check if the phone number is numeric and has exactly 10 digits + const isNumeric = /^\d+$/.test(phoneNumber); + if (phoneNumber.length !== 10 || !isNumeric) { + const row = data["!row#number!"]; + if (!rowMapping[row]) { + rowMapping[row] = []; + } + rowMapping[row].push("The ‘Contact number’ entered is invalid, it should be a 10-digit number and contain only digits. Please update and re-upload."); + } + } else { + const row = data["!row#number!"]; + if (!rowMapping[row]) { + rowMapping[row] = []; + } + rowMapping[row].push("The ‘Contact number’ is a mandatory field in the file. Please update and re-upload."); + } + } +} + + +export function validateEmailSheetWise(datas: any[], localizationMap: any, rowMapping: any) { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; // Simple email regex pattern + + for (const data of datas) { + const emailColumn = getLocalizedName("HCM_ADMIN_CONSOLE_USER_EMAIL_MICROPLAN", localizationMap); + if (data[emailColumn]) { + let email = data[emailColumn].toString(); + + if (!emailRegex.test(email)) { // Validate email format with regex + const row = data["!row#number!"]; + if (!rowMapping[row]) { + rowMapping[row] = []; + } + rowMapping[row].push("The ‘Email’ entered is invalid. Please provide a valid email address and re-upload."); + } + } + } +} + +export function validateNameSheetWise(datas: any[], localizationMap: any, rowMapping: any) { + for (const data of datas) { + const nameColumn = getLocalizedName("HCM_ADMIN_CONSOLE_USER_NAME_MICROPLAN", localizationMap); + if (data[nameColumn]) { + var name = data[nameColumn]; + name = name.toString(); + const row = data["!row#number!"]; + + // Check name length + if (name.length > 128 || name.length < 2) { + if (!rowMapping[row]) { + rowMapping[row] = []; + } + rowMapping[row].push("The ‘Name’ should be between 2 to 128 characters. Please update and re-upload"); + } + else { + // Check if name contains at least one alphabetic character + const hasAlphabetic = /[a-zA-Z]/.test(name); + if (!hasAlphabetic) { + if (!rowMapping[row]) { + rowMapping[row] = []; + } + rowMapping[row].push("The ‘Name’ should contain at least one alphabetic character. Please update and re-upload"); + } + } + + } else { + const row = data["!row#number!"]; + if (!rowMapping[row]) { + rowMapping[row] = []; + } + rowMapping[row].push("The ‘Name’ is a mandatory field in the file. Please update and re-upload"); + } + } +} + + +export function validateUserForMicroplan(data: any, sheetName: any, request: any, errorMap: any, newSchema: any, rowMapping: any, localizationMap: any) { + if (data?.length > 0) { + validatePhoneNumberSheetWise(data, localizationMap, rowMapping); + validateEmailSheetWise(data, localizationMap, rowMapping); + validateNameSheetWise(data, localizationMap, rowMapping); + validateUniqueSheetWise(newSchema, data, request, rowMapping, localizationMap); + } + else { + errorMap[sheetName] = { 2: ["Data rows cannot be empty"] }; + } +} + +export function validateUniqueSheetWise(schema: any, data: any[], request: any, rowMapping: any, localizationMap: any) { + if (schema?.unique) { + const uniqueElements = schema.unique; + + 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 = getLocalizedName(uniqueIdentifierColumnName, localizationMap); + const value = item[element]; + const rowNum = item['!row#number!']; + if (!localizedUniqueIdentifierColumnName || !item[localizedUniqueIdentifierColumnName] && value != undefined) { + if (uniqueMap.has(value)) { + if (!rowMapping[rowNum]) { + rowMapping[rowNum] = []; + } + rowMapping[rowNum].push(`Duplicate value '${value}' found for '${element}'`); + } + // Add the value to the map + uniqueMap.set(value, rowNum); + } + } + } + } +} + +export function validateTargetsForMicroplanCampaigns(data: any, errors: any, localizedTargetColumnNames: any, localizationMap?: { [key: string]: string }) { + 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) => { + var totalTarget = 0, totalTargetSumFromColumns = 0; + for (let i = 0; i < localizedTargetColumnNames.length; i++) { + const targetColumn = localizedTargetColumnNames[i]; + const target = obj[targetColumn]; + if (target !== 0 && !target) { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Data in column '${targetColumn}' can’t be empty, please update the data and re-upload`, + sheetName: key + }); + } else if (typeof target !== 'number') { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Data in column '${targetColumn}' must be a whole number from 1 to 100000000. Please update the data and re-upload.`, + sheetName: key + }); + } else if (target < 1 || target > 100000000) { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Data in column '${targetColumn}' must be a whole number from 1 to 100000000. Please update the data and re-upload.`, + sheetName: key + }); + } else if (!Number.isInteger(target)) { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Data in column '${targetColumn}' must be a whole number from 1 to 100000000. Please update the data and re-upload.`, + sheetName: key + }); + } + if (i == 0) { + totalTarget = target; + } + else { + totalTargetSumFromColumns += target; + } + } + if (totalTargetSumFromColumns > totalTarget) { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Data in other target columns must be less than or equal to '${localizedTargetColumnNames[0]}'`, + sheetName: key + }); + } + }); + } + } + } +} + +export function validateLatLongForMicroplanCampaigns(data: any, errors: any, localizationMap?: { [key: string]: string }) { + 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) => { + for (const column of Object.keys(obj)) { + if (column.toLowerCase().includes('latitude') || column.toLowerCase().includes('longitude')) { + const value = obj[column]; + if (typeof value !== 'number') { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Data in column '${column}' must comply with the guideline structure, please update the data and re-upload`, + sheetName: key + }); + } + } + } + }); + } + } + } +} + + +function validateLatLongForFacility(data: any, errors: any) { + for (const column of Object.keys(data)) { + if (column.toLowerCase().includes('latitude') || column.toLowerCase().includes('longitude')) { + const value = data[column]; + if (typeof value !== 'number') { + errors.push({ + status: "INVALID", + rowNumber: data["!row#number!"], + errorDetails: `Data in column '${column}' must comply with the guideline structure, please update the data and re-upload` + }); + } + } + } +}; + +export function validateMicroplanFacility(request: any, data: any, localizationMap: any) { + const uniqueIdentifierColumnName = getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName, localizationMap); + const activeColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName, localizationMap) : null; + var errors: any = [] + data.forEach((item: any) => { + if (activeColumnName) { + if (!item?.[activeColumnName]) { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${activeColumnName} column can’t be empty, please update the data and re-upload` }); + } + else if (item?.[activeColumnName] != "Active" && item?.[activeColumnName] != "Inactive") { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${activeColumnName} column must be equal to one of the allowed values. Allowed values are Active, Inactive` }); + } + } + const active = activeColumnName ? item[activeColumnName] : "Active"; + if (active == "Active" || !item?.[uniqueIdentifierColumnName]) { + enrichErrorForFcailityMicroplan(request, item, errors, localizationMap); + validateLatLongForFacility(item, errors); + } + }); + 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; + } +} + +function enrichErrorForFcailityMicroplan(request: any, item: any, errors: any = [], localizationMap?: { [key: string]: string }) { + const projectType = request?.body?.projectTypeCode; + const nameColumn = getLocalizedName("HCM_ADMIN_CONSOLE_FACILITY_NAME_MICROPLAN", localizationMap); + if (!item?.[nameColumn]) { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${nameColumn} column can’t be empty, please update the data and re-upload` }) + } + const facilityTypeColumn = getLocalizedName("HCM_ADMIN_CONSOLE_FACILITY_TYPE_MICROPLAN", localizationMap); + if (!item?.[facilityTypeColumn]) { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${facilityTypeColumn} column can’t be empty, please update the data and re-upload` }) + } + const faciltyStatusColumn = getLocalizedName("HCM_ADMIN_CONSOLE_FACILITY_STATUS_MICROPLAN", localizationMap); + if (!item?.[faciltyStatusColumn]) { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${faciltyStatusColumn} column can’t be empty, please update the data and re-upload` }) + } + const facilityCapacityColumn = getLocalizedName(`HCM_ADMIN_CONSOLE_FACILITY_CAPACITY_MICROPLAN_${projectType}`, localizationMap); + if (!item?.[facilityCapacityColumn]) { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${facilityCapacityColumn} column can’t be empty or zero, please update the data and re-upload` }) + } + else if (typeof (item?.[facilityCapacityColumn]) != "number") { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${facilityCapacityColumn} column must be a number in between 1 and 100000000` }) + } + else if (item?.[facilityCapacityColumn] < 1 || item?.[facilityCapacityColumn] > 100000000) { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${facilityCapacityColumn} column must be a number in between 1 and 100000000` }) + } + const fixedPostColumn = getLocalizedName("HCM_ADMIN_CONSOLE_FACILITY_FIXED_POST_MICROPLAN", localizationMap); + if (request?.body?.showFixedPost && !item?.[fixedPostColumn]) { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${fixedPostColumn} column can’t be empty, please update the data and re-upload` }) + } + const boundaryColumn = getLocalizedName("HCM_ADMIN_CONSOLE_RESIDING_BOUNDARY_CODE_MICROPLAN", localizationMap); + if (!item?.[boundaryColumn]) { + errors.push({ status: "INVALID", rowNumber: item?.["!row#number!"], errorDetails: `Data in ${boundaryColumn} column can’t be empty, please update the data and re-upload` }) + } +} + +export function validateFacilityBoundaryForLowestLevel(request: any, boundaries: any, rowData: any, errors: any = [], localizationMap?: { [key: string]: string }) { + if (request?.body?.ResourceDetails?.type == "facility" && request?.body?.ResourceDetails?.additionalDetails?.source == "microplan") { + const hierarchy = request?.body?.hierarchyType?.boundaryHierarchy + const lastLevel = hierarchy?.[hierarchy.length - 1]?.boundaryType + for (const data of rowData?.boundaryCodes) { + const boundaryFromBoundariesType = boundaries.find((boundary: any) => boundary.code == data)?.type + if (boundaryFromBoundariesType != lastLevel) { + errors.push({ status: "INVALID", rowNumber: rowData?.rowNumber, errorDetails: `${data} is not a ${lastLevel} level boundary` }) + } + } + } +} + + + +export async function validateExtraBoundariesForMicroplan(request: any, dataFromSheet: any, localizationMap: any) { + if (await isMicroplanRequest(request)) { + const campaignBoundariesSet = new Set(request?.body?.campaignBoundaries?.map((boundary: any) => boundary.code)); + 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]; + for (const boundaryRow of dataArray) { + const boundaryCode = boundaryRow[getLocalizedName(getBoundaryColumnName(), localizationMap)]; + if (!campaignBoundariesSet.has(boundaryCode)) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Some boundaries in uploaded sheet are not present in campaign boundaries. Please upload from downloaded template only.`); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/health-services/project-factory/tsconfig.debug.json b/health-services/project-factory/tsconfig.debug.json new file mode 100644 index 00000000000..3d14147fd18 --- /dev/null +++ b/health-services/project-factory/tsconfig.debug.json @@ -0,0 +1,68 @@ +{ + "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/tsconfig.json b/health-services/project-factory/tsconfig.json index 5afabc37a6b..8843b6680c1 100644 --- a/health-services/project-factory/tsconfig.json +++ b/health-services/project-factory/tsconfig.json @@ -63,4 +63,4 @@ "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 index 0584dc93095..2f75dbe7f43 100644 --- a/health-services/project-factory/yarn.lock +++ b/health-services/project-factory/yarn.lock @@ -2,35 +2,15 @@ # 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" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== dependencies: "@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": - 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.7": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@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== @@ -38,75 +18,53 @@ "@babel/highlight" "^7.24.7" picocolors "^1.0.0" -"@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/compat-data@^7.25.2": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.4.tgz#7d2a80ce229890edcf4cc259d4d696cb4dae2fcb" + integrity sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ== "@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== + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.2.tgz#ed8eec275118d7613e77a352894cd12ded8eba77" + integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA== 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/generator" "^7.25.0" + "@babel/helper-compilation-targets" "^7.25.2" + "@babel/helper-module-transforms" "^7.25.2" + "@babel/helpers" "^7.25.0" + "@babel/parser" "^7.25.0" + "@babel/template" "^7.25.0" + "@babel/traverse" "^7.25.2" + "@babel/types" "^7.25.2" 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.25.0", "@babel/generator@^7.25.6", "@babel/generator@^7.7.2": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.6.tgz#0df1ad8cb32fe4d2b01d8bf437f153d19342a87c" + integrity sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw== dependencies: - "@babel/types" "^7.24.7" + "@babel/types" "^7.25.6" "@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.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz#e1d9410a90974a3a5a66e84ff55ef62e3c02d06c" + integrity sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw== dependencies: - "@babel/compat-data" "^7.24.7" - "@babel/helper-validator-option" "^7.24.7" - browserslist "^4.22.2" + "@babel/compat-data" "^7.25.2" + "@babel/helper-validator-option" "^7.24.8" + browserslist "^4.23.1" 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-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== - dependencies: - "@babel/template" "^7.24.7" - "@babel/types" "^7.24.7" - -"@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== - dependencies: - "@babel/types" "^7.24.7" - "@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" @@ -115,21 +73,20 @@ "@babel/traverse" "^7.24.7" "@babel/types" "^7.24.7" -"@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.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz#ee713c29768100f2776edf04d4eb23b8d27a66e6" + integrity sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ== 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/traverse" "^7.25.2" -"@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-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.7", "@babel/helper-plugin-utils@^7.24.8", "@babel/helper-plugin-utils@^7.8.0": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz#94ee67e8ec0e5d44ea7baeb51e571bd26af07878" + integrity sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg== "@babel/helper-simple-access@^7.24.7": version "7.24.7" @@ -139,55 +96,28 @@ "@babel/traverse" "^7.24.7" "@babel/types" "^7.24.7" -"@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== - dependencies: - "@babel/types" "^7.24.7" - -"@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-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-string-parser@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" + integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== "@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-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/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== - dependencies: - "@babel/template" "^7.24.7" - "@babel/types" "^7.24.7" +"@babel/helper-validator-option@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d" + integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q== -"@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== +"@babel/helpers@^7.25.0": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.6.tgz#57ee60141829ba2e102f30711ffe3afab357cc60" + integrity sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q== dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - picocolors "^1.0.0" + "@babel/template" "^7.25.0" + "@babel/types" "^7.25.6" "@babel/highlight@^7.24.7": version "7.24.7" @@ -199,181 +129,183 @@ 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.25.0", "@babel/parser@^7.25.6": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.6.tgz#85660c5ef388cbbf6e3d2a694ee97a38f18afe2f" + integrity sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q== + dependencies: + "@babel/types" "^7.25.6" "@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" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" 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" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.8.3": +"@babel/plugin-syntax-class-properties@^7.12.13": version "7.12.13" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-syntax-import-meta@^7.8.3": +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-import-attributes@^7.24.7": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz#6d4c78f042db0e82fd6436cd65fec5dc78ad2bde" + integrity sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.8" + +"@babel/plugin-syntax-import-meta@^7.10.4": version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" 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" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" 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== + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz#39a1fa4a7e3d3d7f34e2acc6be585b718d30e02d" + integrity sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.7" -"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" 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" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.8.3": +"@babel/plugin-syntax-numeric-separator@^7.10.4": version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" 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" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" 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" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" 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" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-top-level-await@^7.8.3": +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" 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== + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.4.tgz#04db9ce5a9043d9c635e75ae7969a2cd50ca97ff" + integrity sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.24.8" -"@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== +"@babel/template@^7.25.0", "@babel/template@^7.3.3": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.0.tgz#e733dc3134b4fede528c15bc95e89cb98c52592a" + integrity sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q== dependencies: "@babel/code-frame" "^7.24.7" - "@babel/parser" "^7.24.7" - "@babel/types" "^7.24.7" - -"@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/parser" "^7.25.0" + "@babel/types" "^7.25.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== +"@babel/traverse@^7.24.7", "@babel/traverse@^7.25.2": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.6.tgz#04fad980e444f182ecf1520504941940a90fea41" + integrity sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ== 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/generator" "^7.25.6" + "@babel/parser" "^7.25.6" + "@babel/template" "^7.25.0" + "@babel/types" "^7.25.6" 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.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.6", "@babel/types@^7.3.3": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.6.tgz#893942ddb858f32ae7a004ec9d3a76b3463ef8e6" + integrity sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw== 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-string-parser" "^7.24.8" "@babel/helper-validator-identifier" "^7.24.7" 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" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" 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" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0" 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" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" 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" + resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a" integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA== dependencies: colorspace "1.1.x" @@ -382,7 +314,7 @@ "@eslint/eslintrc@^0.2.2": version "0.2.2" - resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.2.2.tgz#d01fc791e2fc33e88a29d6f3dc7e93d0cd784b76" integrity sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ== dependencies: ajv "^6.12.4" @@ -398,7 +330,7 @@ "@fast-csv/format@4.3.5": version "4.3.5" - resolved "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz" + resolved "https://registry.yarnpkg.com/@fast-csv/format/-/format-4.3.5.tgz#90d83d1b47b6aaf67be70d6118f84f3e12ee1ff3" integrity sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A== dependencies: "@types/node" "^14.0.1" @@ -410,7 +342,7 @@ "@fast-csv/parse@4.3.6": version "4.3.6" - resolved "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz" + resolved "https://registry.yarnpkg.com/@fast-csv/parse/-/parse-4.3.6.tgz#ee47d0640ca0291034c7aa94039a744cfb019264" integrity sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA== dependencies: "@types/node" "^14.0.1" @@ -428,7 +360,7 @@ "@isaacs/cliui@^8.0.2": version "8.0.2" - resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== dependencies: string-width "^5.1.2" @@ -440,7 +372,7 @@ "@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" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== dependencies: camelcase "^5.3.1" @@ -451,12 +383,12 @@ "@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" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" 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" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== dependencies: "@jest/types" "^29.6.3" @@ -468,7 +400,7 @@ "@jest/core@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== dependencies: "@jest/console" "^29.7.0" @@ -502,7 +434,7 @@ "@jest/environment@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== dependencies: "@jest/fake-timers" "^29.7.0" @@ -512,14 +444,14 @@ "@jest/expect-utils@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" 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" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== dependencies: expect "^29.7.0" @@ -527,7 +459,7 @@ "@jest/fake-timers@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== dependencies: "@jest/types" "^29.6.3" @@ -539,7 +471,7 @@ "@jest/globals@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== dependencies: "@jest/environment" "^29.7.0" @@ -549,7 +481,7 @@ "@jest/reporters@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== dependencies: "@bcoe/v8-coverage" "^0.2.3" @@ -579,14 +511,14 @@ "@jest/schemas@^29.6.3": version "29.6.3" - resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" 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" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== dependencies: "@jridgewell/trace-mapping" "^0.3.18" @@ -595,7 +527,7 @@ "@jest/test-result@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== dependencies: "@jest/console" "^29.7.0" @@ -605,7 +537,7 @@ "@jest/test-sequencer@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== dependencies: "@jest/test-result" "^29.7.0" @@ -615,7 +547,7 @@ "@jest/transform@^29.7.0": version "29.7.0" - resolved "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== dependencies: "@babel/core" "^7.11.6" @@ -636,7 +568,7 @@ "@jest/types@^29.6.3": version "29.6.3" - resolved "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== dependencies: "@jest/schemas" "^29.6.3" @@ -648,7 +580,7 @@ "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== dependencies: "@jridgewell/set-array" "^1.2.1" @@ -657,22 +589,22 @@ "@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" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" 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" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" 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== + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== "@jridgewell/trace-mapping@0.3.9": version "0.3.9" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== dependencies: "@jridgewell/resolve-uri" "^3.0.3" @@ -680,7 +612,7 @@ "@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" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== dependencies: "@jridgewell/resolve-uri" "^3.1.0" @@ -688,7 +620,7 @@ "@npmcli/agent@^2.0.0": version "2.2.2" - resolved "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz" + resolved "https://registry.yarnpkg.com/@npmcli/agent/-/agent-2.2.2.tgz#967604918e62f620a648c7975461c9c9e74fc5d5" integrity sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og== dependencies: agent-base "^7.1.0" @@ -698,59 +630,59 @@ 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.yarnpkg.com/@npmcli/fs/-/fs-3.1.1.tgz#59cdaa5adca95d135fc00f2bb53f5771575ce726" + integrity sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg== 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" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" 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" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" 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" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" 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" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" 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" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" 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" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" 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" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" 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" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" 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" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== dependencies: "@babel/parser" "^7.20.7" @@ -761,29 +693,29 @@ "@types/babel__generator@*": version "7.6.8" - resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" 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" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" 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== + version "7.20.6" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" + integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== 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" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4" integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== dependencies: "@types/connect" "*" @@ -791,22 +723,22 @@ "@types/compression@1.7.5": version "1.7.5" - resolved "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz" + resolved "https://registry.yarnpkg.com/@types/compression/-/compression-1.7.5.tgz#0f80efef6eb031be57b12221c4ba6bc3577808f7" 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" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" 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== + version "4.19.5" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz#218064e321126fcf9048d1ca25dd2465da55d9c6" + integrity sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg== dependencies: "@types/node" "*" "@types/qs" "*" @@ -815,7 +747,7 @@ "@types/express@*", "@types/express@4.17.21": version "4.17.21" - resolved "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d" integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== dependencies: "@types/body-parser" "*" @@ -825,64 +757,64 @@ "@types/graceful-fs@^4.1.3": version "4.1.9" - resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" 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" + resolved "https://registry.yarnpkg.com/@types/hash-sum/-/hash-sum-1.0.2.tgz#32e6e4343ee25914b2a3822f27e8e641ca534f63" 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" + resolved "https://registry.yarnpkg.com/@types/helmet/-/helmet-0.0.47.tgz#ec5161541b649142205b7c558bca14801c5ce129" 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" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== "@types/http-proxy-middleware@^1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@types/http-proxy-middleware/-/http-proxy-middleware-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@types/http-proxy-middleware/-/http-proxy-middleware-1.0.0.tgz#4370a52766782e9c4f0be2ef79c3dd47aef5f428" integrity sha512-/s8lFX6rT43hSPqjjD8KNuu0SkPKY7uIdR6u9DCxVqCRhAvfKxGbVOixJsAT2mdpSnCyrGFAGoB39KFh6tmRxw== dependencies: http-proxy-middleware "*" -"@types/http-proxy@^1.17.10": - version "1.17.14" - resolved "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz" - integrity sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w== +"@types/http-proxy@^1.17.15": + version "1.17.15" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.15.tgz#12118141ce9775a6499ecb4c01d02f90fc839d36" + integrity sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ== dependencies: "@types/node" "*" "@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" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" 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" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" 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" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== dependencies: "@types/istanbul-lib-report" "*" "@types/jaeger-client@^3.18.7": version "3.18.7" - resolved "https://registry.npmjs.org/@types/jaeger-client/-/jaeger-client-3.18.7.tgz" + resolved "https://registry.yarnpkg.com/@types/jaeger-client/-/jaeger-client-3.18.7.tgz#19315eb1616d85b84210da5df01b4a62c219c5b0" integrity sha512-ktEWbcM8faJY5UNEmffnvavjIJ9noNCD7clD9hAZIuQt6QMv0T97kiveH0mbvBNr9SPZXmkidOu/3UWgSy89tQ== dependencies: "@types/node" "*" @@ -891,39 +823,51 @@ "@types/jest@29.5.12": version "29.5.12" - resolved "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.12.tgz#7f7dc6eb4cf246d2474ed78744b05d06ce025544" integrity sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw== dependencies: expect "^29.0.0" pretty-format "^29.0.0" +"@types/lodash@^4.17.5": + version "4.17.7" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.7.tgz#2f776bcb53adc9e13b2c0dfd493dfcbd7de43612" + integrity sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA== + "@types/mime@^1": version "1.3.5" - resolved "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" 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" + resolved "https://registry.yarnpkg.com/@types/morgan/-/morgan-1.9.9.tgz#d60dec3979e16c203a000159daa07d3fb7270d7f" integrity sha512-iRYSDKVaC6FkGSpEVVIvrRGw0DfJMiQzIn3qr2G5B3C//AWkulhXgaBd7tS9/J79GWSYMTHGs7PfI5b3Y8m+RQ== dependencies: "@types/node" "*" -"@types/node@*", "@types/node@20.11.29": +"@types/node@*": + version "22.5.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.5.tgz#52f939dd0f65fc552a4ad0b392f3c466cc5d7a44" + integrity sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA== + dependencies: + undici-types "~6.19.2" + +"@types/node@20.11.29": version "20.11.29" - resolved "https://registry.npmjs.org/@types/node/-/node-20.11.29.tgz" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.29.tgz#431253cede34f392d6aaf7acad427b9c23aa60f6" integrity sha512-P99thMkD/1YkCvAtOd6/zGedKNA0p2fj4ZpjCzcNiSCBWgm3cNRTBfa/qjFnsKkkojxu4vVLtWpesnZ9+ap+gA== dependencies: undici-types "~5.26.4" "@types/node@^14.0.1": version "14.18.63" - resolved "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.63.tgz#1788fa8da838dbb5f9ea994b834278205db6ca2b" integrity sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ== "@types/pg@8.11.3": version "8.11.3" - resolved "https://registry.npmjs.org/@types/pg/-/pg-8.11.3.tgz" + resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.11.3.tgz#f55c81b5ecdb6901636946eccfc7aac5dfc6b840" integrity sha512-xocw4LvpDcj/Ta7bN52tLZm34mso5SZ0Q8fVC0UtD8s85Itip3YHvBeYZhBmC0OThpdOujHsxXtRbEIRxqXPXg== dependencies: "@types/node" "*" @@ -931,18 +875,18 @@ 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.16" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.16.tgz#52bba125a07c0482d26747d5d4947a64daf8f794" + integrity sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A== "@types/range-parser@*": version "1.2.7" - resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb" integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== "@types/send@*": version "0.17.4" - resolved "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a" integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA== dependencies: "@types/mime" "^1" @@ -950,7 +894,7 @@ "@types/serve-static@*": version "1.15.7" - resolved "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714" integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== dependencies: "@types/http-errors" "*" @@ -959,56 +903,56 @@ "@types/stack-utils@^2.0.0": version "2.0.3" - resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" 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" + resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2" 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" + resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1" 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" + resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" 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" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.8.tgz#7545ba4fc3c003d6c756f651f3bf163d8f0f29ba" 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" + resolved "https://registry.yarnpkg.com/@types/xlsx/-/xlsx-0.0.36.tgz#b5062003e5c5374ab4f08fdd3bf69da4d4013af8" 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" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" 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== + version "17.0.33" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" + integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== dependencies: "@types/yargs-parser" "*" abbrev@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" 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" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== dependencies: mime-types "~2.1.34" @@ -1016,39 +960,41 @@ accepts@~1.3.5, accepts@~1.3.8: acorn-jsx@^5.3.1: version "5.3.2" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" 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== + version "8.3.4" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" + integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== + dependencies: + acorn "^8.11.0" acorn@^7.4.0: version "7.4.1" - resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" 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== +acorn@^8.11.0, acorn@^8.4.1: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== adler-32@~1.3.0: version "1.3.1" - resolved "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz" + resolved "https://registry.yarnpkg.com/adler-32/-/adler-32-1.3.1.tgz#1dbf0b36dda0012189a32b3679061932df1821e2" 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" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" 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" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== dependencies: clean-stack "^2.0.0" @@ -1056,12 +1002,12 @@ aggregate-error@^3.0.0: ajv-errors@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-3.0.0.tgz#e54f299f3a3d30fe144161e5f0d8d51196c527bc" integrity sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ== ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: fast-deep-equal "^3.1.1" @@ -1070,74 +1016,74 @@ ajv@^6.10.0, ajv@^6.12.4: uri-js "^4.2.2" ajv@^8.0.1, ajv@^8.16.0: - version "8.16.0" - resolved "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz" - integrity sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw== + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== dependencies: fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" json-schema-traverse "^1.0.0" require-from-string "^2.0.2" - uri-js "^4.4.1" ansi-color@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/ansi-color/-/ansi-color-0.2.1.tgz" + resolved "https://registry.yarnpkg.com/ansi-color/-/ansi-color-0.2.1.tgz#3e75c037475217544ed763a8db5709fa9ae5bf9a" integrity sha512-bF6xLaZBLpOQzgYUtYEhJx090nPSZk1BQ/q2oyBK9aMMcJHzx9uXGCjI2Y+LebsN4Jwoykr0V9whbPiogdyHoQ== ansi-colors@^4.1.1: version "4.1.3" - resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" 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" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" 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" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 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" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" 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== + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== ansi-styles@^3.2.1: version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 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" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 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" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" 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" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" 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" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" @@ -1145,12 +1091,12 @@ anymatch@^3.0.3, anymatch@~3.1.2: aproba@^1.0.3: version "1.2.0" - resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== archiver-utils@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2" integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw== dependencies: glob "^7.1.4" @@ -1166,7 +1112,7 @@ archiver-utils@^2.1.0: archiver-utils@^3.0.4: version "3.0.4" - resolved "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-3.0.4.tgz#a0d201f1cf8fce7af3b5a05aea0a337329e96ec7" integrity sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw== dependencies: glob "^7.2.3" @@ -1182,7 +1128,7 @@ archiver-utils@^3.0.4: archiver@^5.0.0: version "5.3.2" - resolved "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.3.2.tgz#99991d5957e53bd0303a392979276ac4ddccf3b0" integrity sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw== dependencies: archiver-utils "^2.1.0" @@ -1195,7 +1141,7 @@ archiver@^5.0.0: 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" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== dependencies: delegates "^1.0.0" @@ -1203,46 +1149,46 @@ are-we-there-yet@~1.1.2: arg@^4.1.0: version "4.1.3" - resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== argparse@^1.0.7: version "1.0.10" - resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 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" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 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" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== async@^2.6.2: version "2.6.4" - resolved "https://registry.npmjs.org/async/-/async-2.6.4.tgz" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== dependencies: lodash "^4.17.14" async@^3.2.3, async@^3.2.4: - version "3.2.5" - resolved "https://registry.npmjs.org/async/-/async-3.2.5.tgz" - integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== asynckit@^0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 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" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66" integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ== dependencies: follow-redirects "^1.15.6" @@ -1251,7 +1197,7 @@ axios@1.6.8: babel-jest@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== dependencies: "@jest/transform" "^29.7.0" @@ -1264,7 +1210,7 @@ babel-jest@^29.7.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" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -1275,7 +1221,7 @@ babel-plugin-istanbul@^6.1.1: 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" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== dependencies: "@babel/template" "^7.3.3" @@ -1284,26 +1230,29 @@ babel-plugin-jest-hoist@^29.6.3: "@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== + version "1.1.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz#9a929eafece419612ef4ae4f60b1862ebad8ef30" + integrity sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw== 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-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-import-attributes" "^7.24.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" "@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/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" 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" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== dependencies: babel-plugin-jest-hoist "^29.6.3" @@ -1311,34 +1260,34 @@ babel-preset-jest@^29.6.3: balanced-match@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base64-js@^1.3.1: version "1.5.1" - resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== basic-auth@~2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== dependencies: safe-buffer "5.1.2" big-integer@^1.6.17: version "1.6.52" - resolved "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85" integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg== binary-extensions@^2.0.0: version "2.3.0" - resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== binary@~0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz" + resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" integrity sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg== dependencies: buffers "~0.1.1" @@ -1346,19 +1295,19 @@ binary@~0.3.0: bindings@^1.3.1: version "1.5.0" - resolved "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== dependencies: file-uri-to-path "1.0.0" bintrees@1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.2.tgz#49f896d6e858a4a499df85c38fb399b9aff840f8" integrity sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw== bl@^1.0.0: version "1.2.3" - resolved "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7" integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww== dependencies: readable-stream "^2.3.5" @@ -1366,7 +1315,7 @@ bl@^1.0.0: bl@^2.2.0: version "2.2.1" - resolved "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz" + resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.1.tgz#8c11a7b730655c5d56898cdc871224f40fd901d5" integrity sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g== dependencies: readable-stream "^2.3.5" @@ -1374,7 +1323,7 @@ bl@^2.2.0: bl@^4.0.3: version "4.1.0" - resolved "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== dependencies: buffer "^5.5.0" @@ -1383,13 +1332,13 @@ bl@^4.0.3: bluebird@~3.4.1: version "3.4.7" - resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" integrity sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA== -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== +body-parser@1.20.3, body-parser@^1.20.2: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== dependencies: bytes "3.1.2" content-type "~1.0.5" @@ -1399,14 +1348,14 @@ body-parser@1.20.2, body-parser@^1.20.2: http-errors "2.0.0" iconv-lite "0.4.24" on-finished "2.4.1" - qs "6.11.0" + qs "6.13.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" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" @@ -1414,43 +1363,43 @@ brace-expansion@^1.1.7: brace-expansion@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" 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== +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" -browserslist@^4.22.2: - version "4.23.0" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz" - integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== +browserslist@^4.23.1: + version "4.23.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800" + integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== dependencies: - caniuse-lite "^1.0.30001587" - electron-to-chromium "^1.4.668" - node-releases "^2.0.14" - update-browserslist-db "^1.0.13" + caniuse-lite "^1.0.30001646" + electron-to-chromium "^1.5.4" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" bser@2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" 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" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" 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" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== dependencies: buffer-alloc-unsafe "^1.1.0" @@ -1458,27 +1407,27 @@ buffer-alloc@^1.2.0: buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.5: version "0.2.13" - resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" 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" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" 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" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== buffer-indexof-polyfill@~1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz#d2732135c5999c64b277fcf9b1abe3498254729c" integrity sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A== buffer@^5.5.0: version "5.7.1" - resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== dependencies: base64-js "^1.3.1" @@ -1486,19 +1435,19 @@ buffer@^5.5.0: buffermaker@~1.2.0: version "1.2.1" - resolved "https://registry.npmjs.org/buffermaker/-/buffermaker-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/buffermaker/-/buffermaker-1.2.1.tgz#0631f92b891a84b750f1036491ac857c734429f4" 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" + resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" integrity sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ== bufrw@^1.2.1: version "1.4.0" - resolved "https://registry.npmjs.org/bufrw/-/bufrw-1.4.0.tgz" + resolved "https://registry.yarnpkg.com/bufrw/-/bufrw-1.4.0.tgz#58a294ca0bd9ebc880be83001d749706fc996499" integrity sha512-sWm8iPbqvL9+5SiYxXH73UOkyEbGQg7kyHQmReF89WJHQJw2eV4P/yZ0E+b71cczJ4pPobVhXxgQcmfSTgGHxQ== dependencies: ansi-color "^0.2.1" @@ -1508,18 +1457,18 @@ bufrw@^1.2.1: bytes@3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" 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" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" 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.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-18.0.4.tgz#4601d7578dadb59c66044e157d02a3314682d6a5" + integrity sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ== dependencies: "@npmcli/fs" "^3.1.0" fs-minipass "^3.0.0" @@ -1536,7 +1485,7 @@ cacache@^18.0.0: call-bind@^1.0.7: version "1.0.7" - resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== dependencies: es-define-property "^1.0.0" @@ -1547,27 +1496,27 @@ call-bind@^1.0.7: callsites@^3.0.0: version "3.1.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== camelcase@^5.3.1: version "5.3.1" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== camelcase@^6.2.0: version "6.3.0" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" 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== +caniuse-lite@^1.0.30001646: + version "1.0.30001663" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz#1529a723505e429fdfd49532e9fc42273ba7fed7" + integrity sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA== cfb@^1.1.3, cfb@~1.2.1: version "1.2.2" - resolved "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz" + resolved "https://registry.yarnpkg.com/cfb/-/cfb-1.2.2.tgz#94e687628c700e5155436dac05f74e08df23bc44" integrity sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA== dependencies: adler-32 "~1.3.0" @@ -1575,14 +1524,14 @@ cfb@^1.1.3, cfb@~1.2.1: chainsaw@~0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz" + resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" 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" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" @@ -1591,7 +1540,7 @@ chalk@^2.4.2: chalk@^4.0.0: version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" @@ -1599,12 +1548,12 @@ chalk@^4.0.0: char-regex@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" 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" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== dependencies: anymatch "~3.1.2" @@ -1619,32 +1568,32 @@ chokidar@^3.5.1: chownr@^1.0.1: version "1.1.4" - resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== chownr@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" 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" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" 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.4.1" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz#707413784dbb3a72aa11c2f2b042a0bef4004170" + integrity sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA== clean-stack@^2.0.0: version "2.2.0" - resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== cliui@^8.0.1: version "8.0.1" - resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== dependencies: string-width "^4.2.0" @@ -1653,7 +1602,7 @@ cliui@^8.0.1: clone@2.x: version "2.1.2" - resolved "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== cluster-key-slot@^1.1.0: @@ -1663,51 +1612,51 @@ cluster-key-slot@^1.1.0: co@^4.6.0: version "4.6.0" - resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" 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" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== codepage@~1.15.0: version "1.15.0" - resolved "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz" + resolved "https://registry.yarnpkg.com/codepage/-/codepage-1.15.0.tgz#2e00519024b39424ec66eeb3ec07227e692618ab" 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" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== color-convert@^1.9.0, color-convert@^1.9.3: version "1.9.3" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 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" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 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" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 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" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== color-string@^1.6.0: version "1.9.1" - resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== dependencies: color-name "^1.0.0" @@ -1715,7 +1664,7 @@ color-string@^1.6.0: color@^3.1.3: version "3.2.1" - resolved "https://registry.npmjs.org/color/-/color-3.2.1.tgz" + resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== dependencies: color-convert "^1.9.3" @@ -1723,7 +1672,7 @@ color@^3.1.3: colorspace@1.1.x: version "1.1.4" - resolved "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz" + resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.4.tgz#8d442d1186152f60453bf8070cd66eb364e59243" integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== dependencies: color "^3.1.3" @@ -1731,14 +1680,14 @@ colorspace@1.1.x: combined-stream@^1.0.8: version "1.0.8" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" compress-commons@^4.1.2: version "4.1.2" - resolved "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.2.tgz#6542e59cb63e1f46a8b21b0e06f9a32e4c8b06df" integrity sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg== dependencies: buffer-crc32 "^0.2.13" @@ -1748,14 +1697,14 @@ compress-commons@^4.1.2: compressible@~2.0.16: version "2.0.18" - resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" 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" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== dependencies: accepts "~1.3.5" @@ -1768,54 +1717,54 @@ compression@1.7.4: concat-map@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 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" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" 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" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" 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" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" 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" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" 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" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== cookie@0.6.0: version "0.6.0" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== 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" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== crc-32@^1.2.0, 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" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== crc32-stream@^4.0.2: version "4.0.3" - resolved "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-4.0.3.tgz#85dd677eb78fa7cad1ba17cc506a597d41fc6f33" integrity sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw== dependencies: crc-32 "^1.2.0" @@ -1823,7 +1772,7 @@ crc32-stream@^4.0.2: create-jest@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== dependencies: "@jest/types" "^29.6.3" @@ -1836,12 +1785,12 @@ create-jest@^29.7.0: create-require@^1.1.0: version "1.1.1" - resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" 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" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== dependencies: path-key "^3.1.0" @@ -1849,61 +1798,54 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: which "^2.0.1" dayjs@^1.8.34: - version "1.11.11" - resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz" - integrity sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg== + version "1.11.13" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== debug@2.6.9, debug@^2.1.3: version "2.6.9" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 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: - version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== +debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4, debug@^4.3.6: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== dependencies: - ms "2.1.2" - -debug@^4.1.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" + ms "^2.1.3" decompress-response@^3.3.0: version "3.3.0" - resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" 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== + version "1.5.3" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" + integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== deep-extend@^0.6.0: version "0.6.0" - resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" 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" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" 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" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" 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" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== dependencies: es-define-property "^1.0.0" @@ -1912,17 +1854,17 @@ define-data-property@^1.1.4: delayed-stream@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== delegates@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" 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" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== denque@^2.1.0: @@ -1932,112 +1874,117 @@ denque@^2.1.0: depd@2.0.0, depd@~2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" 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" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" 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" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" 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" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" 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" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== diff@^4.0.1: version "4.0.2" - resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== doctrine@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== dependencies: esutils "^2.0.2" duplexer2@~0.1.4: version "0.1.4" - resolved "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" integrity sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA== dependencies: readable-stream "^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" + resolved "https://registry.yarnpkg.com/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz#06e44c223f5e4e94d78ef9db23a6515ce2f962a1" 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" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" 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" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 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== +electron-to-chromium@^1.5.4: + version "1.5.27" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.27.tgz#5203ce5d6054857d84ba84d3681cbe59132ade78" + integrity sha512-o37j1vZqCoEgBuWWXLHQgTN/KDKe7zwpiY5CPeq2RvUqOyJw9xnrULzZAEVQ5p4h+zjMk7hgtOoPdnLxr7m/jw== emittery@^0.13.1: version "0.13.1" - resolved "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" 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" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 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" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== enabled@2.0.x: version "2.0.0" - resolved "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" 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" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + encoding@^0.1.13: version "0.1.13" - resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== dependencies: iconv-lite "^0.6.2" end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" - resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" 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" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== dependencies: ansi-colors "^4.1.1" @@ -2045,64 +1992,71 @@ enquirer@^2.3.5: env-paths@^2.2.0: version "2.2.1" - resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" 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" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" 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" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" -error@7.0.2, error@^7.0.0: +error@7.0.2: version "7.0.2" - resolved "https://registry.npmjs.org/error/-/error-7.0.2.tgz" + resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" integrity sha512-UtVv4l5MhijsYUxPJo4390gzfZvAnTHreNnDjnTZaKIiZ/SemXxAhBkYSKtWa5RtBXbLP8tMgn/n0RUa/H7jXw== dependencies: string-template "~0.2.1" xtend "~4.0.0" +error@^7.0.0: + version "7.2.1" + resolved "https://registry.yarnpkg.com/error/-/error-7.2.1.tgz#eab21a4689b5f684fc83da84a0e390de82d94894" + integrity sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA== + dependencies: + string-template "~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" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" 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" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" 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== +escalade@^3.1.1, escalade@^3.1.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-html@~1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 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" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 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" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== escodegen@^1.8.1: version "1.14.3" - resolved "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== dependencies: esprima "^4.0.1" @@ -2114,7 +2068,7 @@ escodegen@^1.8.1: eslint-scope@^5.1.1: version "5.1.1" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== dependencies: esrecurse "^4.3.0" @@ -2122,24 +2076,24 @@ eslint-scope@^5.1.1: eslint-utils@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== dependencies: eslint-visitor-keys "^1.1.0" eslint-visitor-keys@^1.1.0, 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" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" 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" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== eslint@7.16.0: version "7.16.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-7.16.0.tgz" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.16.0.tgz#a761605bf9a7b32d24bb7cde59aeb0fd76f06092" integrity sha512-iVWPS785RuDA4dWuhhgXTNrGxHHK3a8HLSMBgbbU59ruJDubUraXN8N5rn7kb8tG6sjg74eE0RA3YWT51eusEw== dependencies: "@babel/code-frame" "^7.0.0" @@ -2182,7 +2136,7 @@ eslint@7.16.0: espree@^7.3.0, espree@^7.3.1: version "7.3.1" - resolved "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== dependencies: acorn "^7.4.0" @@ -2191,56 +2145,56 @@ espree@^7.3.0, espree@^7.3.1: esprima@1.2.2: version "1.2.2" - resolved "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.2.tgz#76a0fd66fcfe154fd292667dc264019750b1657b" integrity sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A== esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" - resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== esquery@^1.2.0: - version "1.5.0" - resolved "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz" - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== dependencies: estraverse "^5.1.0" esrecurse@^4.3.0: version "4.3.0" - resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" 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" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" 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" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" 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" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== eventemitter3@^4.0.0: version "4.0.7" - resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== -exceljs@4.4.0: +exceljs@^4.4.0: version "4.4.0" - resolved "https://registry.npmjs.org/exceljs/-/exceljs-4.4.0.tgz" + resolved "https://registry.yarnpkg.com/exceljs/-/exceljs-4.4.0.tgz#cfb1cb8dcc82c760a9fc9faa9e52dadab66b0156" integrity sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg== dependencies: archiver "^5.0.0" @@ -2255,7 +2209,7 @@ exceljs@4.4.0: execa@^5.0.0: version "5.1.1" - resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== dependencies: cross-spawn "^7.0.3" @@ -2270,17 +2224,17 @@ execa@^5.0.0: exit@^0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" 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" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" 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" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== dependencies: "@jest/expect-utils" "^29.7.0" @@ -2291,40 +2245,40 @@ expect@^29.0.0, expect@^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" + resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6" integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== express@^4.19.2: - version "4.19.2" - resolved "https://registry.npmjs.org/express/-/express-4.19.2.tgz" - integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== + version "4.21.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.0.tgz#d57cb706d49623d4ac27833f1cbc466b668eb915" + integrity sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng== dependencies: accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.20.2" + body-parser "1.20.3" content-disposition "0.5.4" content-type "~1.0.4" cookie "0.6.0" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.2.0" + finalhandler "1.3.1" fresh "0.5.2" http-errors "2.0.0" - merge-descriptors "1.0.1" + merge-descriptors "1.0.3" methods "~1.1.2" on-finished "2.4.1" parseurl "~1.3.3" - path-to-regexp "0.1.7" + path-to-regexp "0.1.10" proxy-addr "~2.0.7" - qs "6.11.0" + qs "6.13.0" range-parser "~1.2.1" safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" + send "0.19.0" + serve-static "1.16.2" setprototypeof "1.2.0" statuses "2.0.1" type-is "~1.6.18" @@ -2333,7 +2287,7 @@ express@^4.19.2: fast-csv@^4.3.1: version "4.3.6" - resolved "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz" + resolved "https://registry.yarnpkg.com/fast-csv/-/fast-csv-4.3.6.tgz#70349bdd8fe4d66b1130d8c91820b64a21bc4a63" integrity sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw== dependencies: "@fast-csv/format" "4.3.5" @@ -2341,57 +2295,62 @@ fast-csv@^4.3.1: 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" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" 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" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" 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" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-uri@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.1.tgz#cddd2eecfc83a71c1be2cc2ef2061331be8a7134" + integrity sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw== + fb-watchman@^2.0.0: version "2.0.2" - resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" 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" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== file-entry-cache@^6.0.0: version "6.0.1" - resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" 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" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" 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== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== 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== +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== dependencies: debug "2.6.9" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" on-finished "2.4.1" parseurl "~1.3.3" @@ -2400,7 +2359,7 @@ finalhandler@1.2.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" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== dependencies: locate-path "^5.0.0" @@ -2408,7 +2367,7 @@ find-up@^4.0.0, find-up@^4.1.0: flat-cache@^3.0.4: version "3.2.0" - resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== dependencies: flatted "^3.2.9" @@ -2417,30 +2376,30 @@ flat-cache@^3.0.4: flatted@^3.2.9: version "3.3.1" - resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" 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" + resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== follow-redirects@^1.0.0, 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== + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== 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.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== 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" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== dependencies: asynckit "^0.4.0" @@ -2449,41 +2408,41 @@ form-data@^4.0.0: forwarded@0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== frac@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/frac/-/frac-1.1.2.tgz#3d74f7f6478c88a1b5020306d747dc6313c74d0b" integrity sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA== fresh@0.5.2: version "0.5.2" - resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 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" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" 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" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" 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" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-3.0.3.tgz#79a85981c4dc120065e96f62086bf6f9dc26cc54" 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" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@^2.3.2, fsevents@~2.3.2: @@ -2493,7 +2452,7 @@ fsevents@^2.3.2, fsevents@~2.3.2: fstream@^1.0.12: version "1.0.12" - resolved "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== dependencies: graceful-fs "^4.1.2" @@ -2503,17 +2462,17 @@ fstream@^1.0.12: function-bind@^1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" 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" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" 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" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" integrity sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg== dependencies: aproba "^1.0.3" @@ -2527,17 +2486,17 @@ gauge@~2.7.3: 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" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" 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" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 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" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== dependencies: es-errors "^1.3.0" @@ -2548,40 +2507,41 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: 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" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" 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" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" 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" + resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== glob-parent@^5.0.0, glob-parent@~5.1.2: version "5.1.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: 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.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== 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" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" glob@^7.1.3, glob@^7.1.4, glob@^7.2.3: version "7.2.3" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: fs.realpath "^1.0.0" @@ -2593,80 +2553,80 @@ glob@^7.1.3, glob@^7.1.4, glob@^7.2.3: globals@^11.1.0: version "11.12.0" - resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^12.1.0: version "12.4.0" - resolved "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== dependencies: type-fest "^0.8.1" gopd@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== dependencies: get-intrinsic "^1.1.3" graceful-fs@^4.1.2, graceful-fs@^4.2.0, graceful-fs@^4.2.2, 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" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" 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" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 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" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 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" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" 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" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" 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" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" 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" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" 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" + resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a" integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg== -hasown@^2.0.0: +hasown@^2.0.0, hasown@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" 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" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-7.1.0.tgz#287279e00f8a3763d5dccbaf1e5ee39b8c3784ca" integrity sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg== hexer@^1.5.0: version "1.5.0" - resolved "https://registry.npmjs.org/hexer/-/hexer-1.5.0.tgz" + resolved "https://registry.yarnpkg.com/hexer/-/hexer-1.5.0.tgz#b86ce808598e8a9d1892c571f3cedd86fc9f0653" integrity sha512-dyrPC8KzBzUJ19QTIo1gXNqIISRXQ0NwteW6OeQHRN4ZuZeHkdODfj0zHBdOlHbRY8GqbqK57C9oWSvQZizFsg== dependencies: ansi-color "^0.2.1" @@ -2676,17 +2636,17 @@ hexer@^1.5.0: html-escaper@^2.0.0: version "2.0.2" - resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" 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" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" 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" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== dependencies: depd "2.0.0" @@ -2697,27 +2657,27 @@ http-errors@2.0.0: 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" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== dependencies: agent-base "^7.1.0" debug "^4.3.4" http-proxy-middleware@*, http-proxy-middleware@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.0.tgz" - integrity sha512-36AV1fIaI2cWRzHo+rbcxhe3M3jUDCNzc4D5zRl57sEWRAxdXYtw7FSQKYY6PDKssiAKjLYypbssHk+xs/kMXw== + version "3.0.2" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-3.0.2.tgz#c834aad7cac47a229205399ab64a102e9bbed820" + integrity sha512-fBLFpmvDzlxdckwZRjM0wWtwDZ4KBtQ8NFqhrFKoEtK4myzuiumBuNTxD+F4cVbXfOZljIbrynmvByofDzT7Ag== dependencies: - "@types/http-proxy" "^1.17.10" - debug "^4.3.4" + "@types/http-proxy" "^1.17.15" + debug "^4.3.6" http-proxy "^1.18.1" - is-glob "^4.0.1" - is-plain-obj "^3.0.0" - micromatch "^4.0.5" + is-glob "^4.0.3" + is-plain-object "^5.0.0" + micromatch "^4.0.8" http-proxy@^1.18.1: version "1.18.1" - resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== dependencies: eventemitter3 "^4.0.0" @@ -2725,76 +2685,76 @@ http-proxy@^1.18.1: requires-port "^1.0.0" 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== + version "7.0.5" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" + integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== 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" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" 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" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 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" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== dependencies: safer-buffer ">= 2.1.2 < 3.0.0" ieee754@^1.1.13: version "1.2.1" - resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== ignore@^4.0.6: version "4.0.6" - resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" 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" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" 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" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" 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== + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== 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" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 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" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" 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" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" @@ -2802,12 +2762,12 @@ inflight@^1.0.4: inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3: version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 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" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== ioredis@^5.4.1: @@ -2827,7 +2787,7 @@ ioredis@^5.4.1: ip-address@^9.0.5: version "9.0.5" - resolved "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz" + resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a" integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g== dependencies: jsbn "1.1.0" @@ -2835,105 +2795,105 @@ ip-address@^9.0.5: ipaddr.js@1.9.1: version "1.9.1" - resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" 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" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" 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" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" 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" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 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== + version "2.15.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" + integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== dependencies: - hasown "^2.0.0" + hasown "^2.0.2" is-extglob@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 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" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 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" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 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" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 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" + resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" 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" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-plain-obj@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz" - integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== is-stream@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== isarray@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== isexe@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== isexe@^3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-3.1.1.tgz#4a407e2bd78ddfb14bea0c27c6f7072dde775f0d" 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" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" 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" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== dependencies: "@babel/core" "^7.12.3" @@ -2943,9 +2903,9 @@ istanbul-lib-instrument@^5.0.4: 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== + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== dependencies: "@babel/core" "^7.23.9" "@babel/parser" "^7.23.9" @@ -2955,7 +2915,7 @@ istanbul-lib-instrument@^6.0.0: 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" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== dependencies: istanbul-lib-coverage "^3.0.0" @@ -2964,7 +2924,7 @@ istanbul-lib-report@^3.0.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" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== dependencies: debug "^4.1.1" @@ -2973,16 +2933,16 @@ istanbul-lib-source-maps@^4.0.0: istanbul-reports@^3.1.3: version "3.1.7" - resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" 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== +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== dependencies: "@isaacs/cliui" "^8.0.2" optionalDependencies: @@ -2990,7 +2950,7 @@ jackspeak@^2.3.6: jaeger-client@^3.19.0: version "3.19.0" - resolved "https://registry.npmjs.org/jaeger-client/-/jaeger-client-3.19.0.tgz" + resolved "https://registry.yarnpkg.com/jaeger-client/-/jaeger-client-3.19.0.tgz#9b5bd818ebd24e818616ee0f5cffe1722a53ae6e" integrity sha512-M0c7cKHmdyEUtjemnJyx/y9uX16XHocL46yQvyqDlPdvAcwPDbHrIbKjQdBqtiE4apQ/9dmr+ZLJYYPGnurgpw== dependencies: node-int64 "^0.4.0" @@ -3001,7 +2961,7 @@ jaeger-client@^3.19.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" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== dependencies: execa "^5.0.0" @@ -3010,7 +2970,7 @@ jest-changed-files@^29.7.0: jest-circus@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== dependencies: "@jest/environment" "^29.7.0" @@ -3036,7 +2996,7 @@ jest-circus@^29.7.0: jest-cli@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== dependencies: "@jest/core" "^29.7.0" @@ -3053,7 +3013,7 @@ jest-cli@^29.7.0: jest-config@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== dependencies: "@babel/core" "^7.11.6" @@ -3081,7 +3041,7 @@ jest-config@^29.7.0: jest-diff@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== dependencies: chalk "^4.0.0" @@ -3091,14 +3051,14 @@ jest-diff@^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" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" 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" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== dependencies: "@jest/types" "^29.6.3" @@ -3109,7 +3069,7 @@ jest-each@^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" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== dependencies: "@jest/environment" "^29.7.0" @@ -3121,12 +3081,12 @@ jest-environment-node@^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" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" 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" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== dependencies: "@jest/types" "^29.6.3" @@ -3145,7 +3105,7 @@ jest-haste-map@^29.7.0: 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" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== dependencies: jest-get-type "^29.6.3" @@ -3153,7 +3113,7 @@ jest-leak-detector@^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" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== dependencies: chalk "^4.0.0" @@ -3163,7 +3123,7 @@ jest-matcher-utils@^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" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== dependencies: "@babel/code-frame" "^7.12.13" @@ -3178,7 +3138,7 @@ jest-message-util@^29.7.0: jest-mock@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== dependencies: "@jest/types" "^29.6.3" @@ -3187,17 +3147,17 @@ jest-mock@^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" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" 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" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" 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" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== dependencies: jest-regex-util "^29.6.3" @@ -3205,7 +3165,7 @@ jest-resolve-dependencies@^29.7.0: jest-resolve@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== dependencies: chalk "^4.0.0" @@ -3220,7 +3180,7 @@ jest-resolve@^29.7.0: jest-runner@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== dependencies: "@jest/console" "^29.7.0" @@ -3247,7 +3207,7 @@ jest-runner@^29.7.0: jest-runtime@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== dependencies: "@jest/environment" "^29.7.0" @@ -3275,7 +3235,7 @@ jest-runtime@^29.7.0: jest-snapshot@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== dependencies: "@babel/core" "^7.11.6" @@ -3301,7 +3261,7 @@ jest-snapshot@^29.7.0: jest-util@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== dependencies: "@jest/types" "^29.6.3" @@ -3313,7 +3273,7 @@ jest-util@^29.7.0: jest-validate@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== dependencies: "@jest/types" "^29.6.3" @@ -3325,7 +3285,7 @@ jest-validate@^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" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== dependencies: "@jest/test-result" "^29.7.0" @@ -3339,7 +3299,7 @@ jest-watcher@^29.7.0: jest-worker@^29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== dependencies: "@types/node" "*" @@ -3349,7 +3309,7 @@ jest-worker@^29.7.0: jest@29.7.0: version "29.7.0" - resolved "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== dependencies: "@jest/core" "^29.7.0" @@ -3359,12 +3319,12 @@ jest@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" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 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" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== dependencies: argparse "^1.0.7" @@ -3372,47 +3332,47 @@ js-yaml@^3.13.1: jsbn@1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" 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" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" 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" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" 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" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" 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" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" 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" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" 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" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== json5@^2.2.3: version "2.2.3" - resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" 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" + resolved "https://registry.yarnpkg.com/jsonpath/-/jsonpath-1.1.1.tgz#0ca1ed8fb65bb3309248cc9d5466d12d5b0b9901" integrity sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w== dependencies: esprima "1.2.2" @@ -3421,7 +3381,7 @@ jsonpath@1.1.1: jszip@^3.10.1, jszip@^3.2.2: version "3.10.1" - resolved "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== dependencies: lie "~3.3.0" @@ -3431,7 +3391,7 @@ jszip@^3.10.1, jszip@^3.2.2: kafka-node@5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/kafka-node/-/kafka-node-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/kafka-node/-/kafka-node-5.0.0.tgz#4b6f65cc1d77ebe565859dfb8f9575ed15d543c0" integrity sha512-dD2ga5gLcQhsq1yNoQdy1MU4x4z7YnXM5bcG9SdQuiNr5KKuAmXixH1Mggwdah5o7EfholFbcNDPSVA6BIfaug== dependencies: async "^2.6.2" @@ -3452,36 +3412,36 @@ kafka-node@5.0.0: keyv@^4.5.3: version "4.5.4" - resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" 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" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== kuler@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== lazystream@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638" integrity sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw== dependencies: readable-stream "^2.0.5" leven@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" 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" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== dependencies: prelude-ls "^1.2.1" @@ -3489,7 +3449,7 @@ levn@^0.4.1: levn@~0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== dependencies: prelude-ls "~1.1.2" @@ -3497,51 +3457,51 @@ levn@~0.3.0: lie@~3.3.0: version "3.3.0" - resolved "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" 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" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== listenercount@~1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937" integrity sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ== locate-path@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== dependencies: p-locate "^4.1.0" lodash.defaults@^4.2.0: version "4.2.0" - resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== lodash.difference@^4.5.0: version "4.5.0" - resolved "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz" + resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" integrity sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA== lodash.escaperegexp@^4.1.2: version "4.1.2" - resolved "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz" + resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347" integrity sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw== lodash.flatten@^4.4.0: version "4.4.0" - resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== lodash.groupby@^4.6.0: version "4.6.0" - resolved "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz" + resolved "https://registry.yarnpkg.com/lodash.groupby/-/lodash.groupby-4.6.0.tgz#0b08a1dcf68397c397855c3239783832df7403d1" integrity sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw== lodash.isarguments@^3.1.0: @@ -3551,58 +3511,58 @@ lodash.isarguments@^3.1.0: lodash.isboolean@^3.0.3: version "3.0.3" - resolved "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== lodash.isequal@^4.5.0: version "4.5.0" - resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== lodash.isfunction@^3.0.9: version "3.0.9" - resolved "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz" + resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw== lodash.isnil@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/lodash.isnil/-/lodash.isnil-4.0.0.tgz#49e28cd559013458c814c5479d3c663a21bfaa6c" integrity sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng== lodash.isplainobject@^4.0.6: version "4.0.6" - resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== lodash.isundefined@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz#23ef3d9535565203a66cefd5b830f848911afb48" integrity sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA== lodash.truncate@^4.4.2: version "4.4.2" - resolved "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz" + resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== lodash.union@^4.6.0: version "4.6.0" - resolved "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz" + resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" integrity sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw== lodash.uniq@^4.5.0: version "4.5.0" - resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" 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: version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 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== +logform@^2.4.0, logform@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.6.1.tgz#71403a7d8cae04b2b734147963236205db9b3df0" + integrity sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA== dependencies: "@colors/colors" "1.6.0" "@types/triple-beam" "^1.3.2" @@ -3613,49 +3573,42 @@ logform@^2.3.2, logform@^2.4.0: long@1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/long/-/long-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/long/-/long-1.1.2.tgz#eaef5951ca7551d96926b82da242db9d6b28fb53" 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" + resolved "https://registry.yarnpkg.com/long/-/long-2.4.0.tgz#9fa180bb1d9500cdc29c4156766a1995e1f4524f" integrity sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ== 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.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== lru-cache@^5.1.1: version "5.1.1" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" 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" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" 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" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" 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.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz#273ba2f78f45e1f3a6dca91cede87d9fa4821e36" + integrity sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA== dependencies: "@npmcli/agent" "^2.0.0" cacache "^18.0.0" @@ -3666,108 +3619,114 @@ 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" makeerror@1.0.12: version "1.0.12" - resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" 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" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 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-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== merge-stream@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" 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" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== -micromatch@^4.0.4, micromatch@^4.0.5: - version "4.0.5" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== +micromatch@^4.0.4, micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" -mime-db@1.52.0, "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" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== +"mime-db@>= 1.43.0 < 2": + version "1.53.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.53.0.tgz#3cb63cd820fc29896d9d4e8c32ab4fcd74ccb447" + integrity sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg== + 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" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" 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" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" 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" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" 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" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" 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" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" minimatch@^5.1.0: version "5.1.6" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.1: - version "9.0.4" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz" - integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: brace-expansion "^2.0.1" minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.6: version "1.2.8" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" 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" + resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-2.0.1.tgz#1621bc77e12258a12c60d34e2276ec5c20680863" 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== + version "3.0.5" + resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-3.0.5.tgz#f0f97e40580affc4a35cc4a1349f05ae36cb1e4c" + integrity sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg== dependencies: minipass "^7.0.3" minipass-sized "^1.0.3" @@ -3777,45 +3736,45 @@ minipass-fetch@^3.0.0: minipass-flush@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" 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" + resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" 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" + resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" 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" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== dependencies: yallist "^4.0.0" minipass@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" 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== +"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.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" - resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== dependencies: minipass "^3.0.0" @@ -3823,19 +3782,19 @@ minizlib@^2.1.1, minizlib@^2.1.2: "mkdirp@>=0.5 0", mkdirp@^0.5.1: version "0.5.6" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: minimist "^1.2.6" mkdirp@^1.0.3, mkdirp@^1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== morgan@1.10.0: version "1.10.0" - resolved "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7" integrity sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ== dependencies: basic-auth "~2.0.1" @@ -3846,61 +3805,56 @@ morgan@1.10.0: ms@2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 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, ms@^2.1.1: +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" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" 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== + version "2.20.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.20.0.tgz#08c5ea813dd54ed16e5bd6505bf42af4f7838ca3" + integrity sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw== 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" + resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" 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" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" 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" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" 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" + resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz#26c8a3cee6cc05fbcf1e333cd2fc3e003326c0b5" 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" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.30.1.tgz#c437d4b1fe0e285aaf290d45b45d4d7afedac4cf" 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" + resolved "https://registry.yarnpkg.com/node-cache/-/node-cache-5.1.2.tgz#f264dc2ccad0a780e76253a694e9fd0ed19c398d" integrity sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg== dependencies: clone "2.x" node-gyp@10.0.1: version "10.0.1" - resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-10.0.1.tgz#205514fc19e5830fa991e4a689f9e81af377a966" integrity sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg== dependencies: env-paths "^2.2.0" @@ -3916,41 +3870,41 @@ node-gyp@10.0.1: node-int64@^0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" 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== +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== noop-logger@^0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz" + resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" 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.yarnpkg.com/nopt/-/nopt-7.2.1.tgz#1cac0eab9b8e97c9093338446eddd40b2c8ca1e7" + integrity sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w== 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" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 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" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" 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" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== dependencies: are-we-there-yet "~1.1.2" @@ -3960,77 +3914,77 @@ npmlog@^4.0.1: 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" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 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" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 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== + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== obuf@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" 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" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" 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" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== 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" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" 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" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 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" + resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45" 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" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== dependencies: mimic-fn "^2.1.0" opentracing@^0.14.4, opentracing@^0.14.7, opentracing@~0.14.3: version "0.14.7" - resolved "https://registry.npmjs.org/opentracing/-/opentracing-0.14.7.tgz" + resolved "https://registry.yarnpkg.com/opentracing/-/opentracing-0.14.7.tgz#25d472bd0296dc0b64d7b94cbc995219031428f5" integrity sha512-vz9iS7MJ5+Bp1URw8Khvdyw1H/hGvzHWlKQ7eRrQojSCDL1/SrWfrY9QebLw97n2deyRtzHRC3MkQfVNUCo91Q== optional@^0.1.3: version "0.1.4" - resolved "https://registry.npmjs.org/optional/-/optional-0.1.4.tgz" + resolved "https://registry.yarnpkg.com/optional/-/optional-0.1.4.tgz#cdb1a9bedc737d2025f690ceeb50e049444fd5b3" integrity sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw== optionator@^0.8.1: version "0.8.3" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== dependencies: deep-is "~0.1.3" @@ -4041,70 +3995,75 @@ 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.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + 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" - resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 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" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" 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" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" 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" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" 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" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" 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" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +package-json-from-dist@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" + integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== + pako@~1.0.2: version "1.0.11" - resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" 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" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" 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" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== dependencies: "@babel/code-frame" "^7.0.0" @@ -4114,75 +4073,75 @@ parse-json@^5.2.0: parseurl@~1.3.3: version "1.3.3" - resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" 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" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" 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" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 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" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" 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" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" 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.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== 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== +path-to-regexp@0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" + integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== pg-cloudflare@^1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz#e6d5833015b170e23ae819e8c5d7eaedb472ca98" integrity sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q== pg-connection-string@^2.6.4: - 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== + version "2.7.0" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.7.0.tgz#f1d3489e427c62ece022dba98d5262efcb168b37" + integrity sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA== pg-int8@1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" 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" + resolved "https://registry.yarnpkg.com/pg-numeric/-/pg-numeric-1.0.2.tgz#816d9a44026086ae8ae74839acd6a09b0636aa3a" integrity sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw== pg-pool@^3.6.2: - 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== + version "3.7.0" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.7.0.tgz#d4d3c7ad640f8c6a2245adc369bafde4ebb8cbec" + integrity sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g== pg-protocol@*, pg-protocol@^1.6.1: - version "1.6.1" - resolved "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.1.tgz" - integrity sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg== + version "1.7.0" + resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.7.0.tgz#ec037c87c20515372692edac8b63cf4405448a93" + integrity sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ== pg-types@^2.1.0: version "2.2.0" - resolved "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== dependencies: pg-int8 "1.0.1" @@ -4193,7 +4152,7 @@ pg-types@^2.1.0: pg-types@^4.0.1: version "4.0.2" - resolved "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-4.0.2.tgz#399209a57c326f162461faa870145bb0f918b76d" integrity sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng== dependencies: pg-int8 "1.0.1" @@ -4206,7 +4165,7 @@ pg-types@^4.0.1: pg@8.12.0: version "8.12.0" - resolved "https://registry.npmjs.org/pg/-/pg-8.12.0.tgz" + resolved "https://registry.yarnpkg.com/pg/-/pg-8.12.0.tgz#9341724db571022490b657908f65aee8db91df79" integrity sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ== dependencies: pg-connection-string "^2.6.4" @@ -4219,85 +4178,85 @@ pg@8.12.0: pgpass@1.x: version "1.0.5" - resolved "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d" 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== +picocolors@^1.0.0, picocolors@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== 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" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pirates@^4.0.4: version "4.0.6" - resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" 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" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" 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" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" 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" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-3.0.2.tgz#68d6182cb0f7f152a7e60dc6a6889ed74b0a5f98" 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" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" 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" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-3.0.0.tgz#9048dc461ac7ba70a6a42d109221619ecd1cb089" 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" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" 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" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-2.1.0.tgz#b85d3c1fb6fb3c6c8db1e9942a13a3bf625189d0" 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" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" 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" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-3.0.0.tgz#baf7a8b3ebab19b7f38f07566c7aab0962f0c86a" 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" + resolved "https://registry.yarnpkg.com/postgres-range/-/postgres-range-1.1.4.tgz#a59c5f9520909bcec5e63e8cf913a92e4c952863" 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" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.3.0.tgz#58b4d8344e03590990931ee088dd5401b03004c8" integrity sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg== dependencies: detect-libc "^1.0.3" @@ -4319,17 +4278,17 @@ prebuild-install@5.3.0: prelude-ls@^1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" 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" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" 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" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== dependencies: "@jest/schemas" "^29.6.3" @@ -4338,34 +4297,39 @@ pretty-format@^29.0.0, pretty-format@^29.7.0: proc-log@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-3.0.0.tgz#fb05ef83ccd64fd7b20bbe9c8c1070fc08338dd8" integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A== +proc-log@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-4.2.0.tgz#b6f461e4026e75fdfe228b265e9f7a00779d7034" + 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" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== process@^0.10.0: version "0.10.1" - resolved "https://registry.npmjs.org/process/-/process-0.10.1.tgz" + resolved "https://registry.yarnpkg.com/process/-/process-0.10.1.tgz#842457cc51cfed72dc775afeeafb8c6034372725" integrity sha512-dyIett8dgGIZ/TXKUzeYExt7WA6ldDzys9vTDU/cCA9L17Ypme+KzS+NjQCjpn9xsvi/shbMC+yP/BcFMBz0NA== progress@^2.0.0: version "2.0.3" - resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== "prom-client@~11.3.0 || ^12.0.0 || ^13.0.0 || ^14.0.0": version "14.2.0" - resolved "https://registry.npmjs.org/prom-client/-/prom-client-14.2.0.tgz" + resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-14.2.0.tgz#ca94504e64156f6506574c25fb1c34df7812cf11" integrity sha512-sF308EhTenb/pDRPakm+WgiN+VdM/T1RaHj1x+MvAuT8UiQP8JmOEbxVqtkbfR4LrvOg5n7ic01kRBDGXjYikA== dependencies: tdigest "^0.1.1" promise-retry@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== dependencies: err-code "^2.0.2" @@ -4373,7 +4337,7 @@ promise-retry@^2.0.1: prompts@^2.0.1: version "2.4.2" - resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== dependencies: kleur "^3.0.3" @@ -4381,12 +4345,12 @@ prompts@^2.0.1: property-expr@^2.0.5: version "2.0.6" - resolved "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz" + resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.6.tgz#f77bc00d5928a6c748414ad12882e83f24aec1e8" 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" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== dependencies: forwarded "0.2.0" @@ -4394,12 +4358,12 @@ proxy-addr@~2.0.7: 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" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== pump@^1.0.0: version "1.0.3" - resolved "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw== dependencies: end-of-stream "^1.1.0" @@ -4407,7 +4371,7 @@ pump@^1.0.0: pump@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== dependencies: end-of-stream "^1.1.0" @@ -4415,29 +4379,29 @@ pump@^2.0.1: punycode@^2.1.0: version "2.3.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" 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" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" 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== +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== dependencies: - side-channel "^1.0.4" + side-channel "^1.0.6" range-parser@~1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" 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" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== dependencies: bytes "3.1.2" @@ -4447,7 +4411,7 @@ raw-body@2.5.2: rc@^1.2.7: version "1.2.8" - resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== dependencies: deep-extend "^0.6.0" @@ -4456,13 +4420,13 @@ 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.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + 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" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== dependencies: core-util-is "~1.0.0" @@ -4473,9 +4437,9 @@ readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0, readable-stream@^3.6.2: version "3.6.2" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== dependencies: inherits "^2.0.3" @@ -4484,14 +4448,14 @@ readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: readdir-glob@^1.1.2: version "1.1.3" - resolved "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz" + resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.3.tgz#c3d831f51f5e7bfa62fa2ffbe4b508c640f09584" integrity sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA== dependencies: minimatch "^5.1.0" readdirp@~3.6.0: version "3.6.0" - resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== dependencies: picomatch "^2.2.1" @@ -4510,49 +4474,49 @@ redis-parser@^3.0.0: regexpp@^3.1.0: version "3.2.0" - resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" 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" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 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" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== requires-port@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== resolve-cwd@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" 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" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" 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" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" 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" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" 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" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: is-core-module "^2.13.0" @@ -4561,81 +4525,79 @@ resolve@^1.0.0, resolve@^1.20.0: retry@^0.10.1: version "0.10.1" - resolved "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" integrity sha512-ZXUSQYTHdl3uS7IuCehYfMzKyIDBNoAuUblvy5oGO5UJSUTmStUUVPXbA9Qxd173Bgre53yCQczQuHgRWAdvJQ== retry@^0.12.0: version "0.12.0" - resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== rimraf@2, rimraf@^2.6.1: version "2.7.1" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" 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" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== 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: +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.1: +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.2.0: version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 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== + version "2.5.0" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" + integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== "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" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 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== + version "1.4.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" + integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== saxes@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== dependencies: xmlchars "^2.2.0" semver@^5.4.1: version "5.7.2" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== semver@^6.3.0, semver@^6.3.1: version "6.3.1" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" 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" + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== -send@0.18.0: - version "0.18.0" - resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== dependencies: debug "2.6.9" depd "2.0.0" @@ -4651,24 +4613,24 @@ send@0.18.0: 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== +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== dependencies: - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" parseurl "~1.3.3" - send "0.18.0" + send "0.19.0" set-blocking@~2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 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" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== dependencies: define-data-property "^1.1.4" @@ -4680,29 +4642,29 @@ set-function-length@^1.2.1: setimmediate@^1.0.5, setimmediate@~1.0.4: version "1.0.5" - resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" 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" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" 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" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" 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" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -side-channel@^1.0.4: +side-channel@^1.0.6: version "1.0.6" - resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== dependencies: call-bind "^1.0.7" @@ -4712,22 +4674,22 @@ side-channel@^1.0.4: 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" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" 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" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" 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" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" 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" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.2.tgz#5708fb0919d440657326cd5fe7d2599d07705019" integrity sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw== dependencies: decompress-response "^3.3.0" @@ -4736,24 +4698,24 @@ simple-get@^2.7.0: simple-swizzle@^0.2.2: version "0.2.2" - resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" 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" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== slash@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" 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" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== dependencies: ansi-styles "^4.0.0" @@ -4762,12 +4724,12 @@ slice-ansi@^4.0.0: smart-buffer@^4.2.0: version "4.2.0" - resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== snappy@^6.0.1: version "6.3.5" - resolved "https://registry.npmjs.org/snappy/-/snappy-6.3.5.tgz" + resolved "https://registry.yarnpkg.com/snappy/-/snappy-6.3.5.tgz#c14b8dea8e9bc2687875b5e491d15dd900e6023c" integrity sha512-lonrUtdp1b1uDn1dbwgQbBsb5BbaiLeKq+AGwOk2No+en+VvJThwmtztwulEQsLinRF681pBqib0NUZaizKLIA== dependencies: bindings "^1.3.1" @@ -4775,72 +4737,80 @@ snappy@^6.0.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== + version "8.0.4" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz#9071dca17af95f483300316f4b063578fa0db08c" + integrity sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw== dependencies: agent-base "^7.1.1" debug "^4.3.4" - socks "^2.7.1" + socks "^2.8.3" -socks@^2.7.1: - version "2.8.1" - resolved "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz" - integrity sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ== +socks@^2.8.3: + version "2.8.3" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.3.tgz#1ebd0f09c52ba95a09750afe3f3f9f724a800cb5" + 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.13: version "0.5.13" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" +source-map-support@^0.5.12: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + 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" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== split2@^4.1.0: version "4.2.0" - resolved "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" 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" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" 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" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== ssf@~0.11.2: version "0.11.2" - resolved "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz" + resolved "https://registry.yarnpkg.com/ssf/-/ssf-0.11.2.tgz#0b99698b237548d088fc43cdf2b70c1a7512c06c" 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== + version "10.0.6" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-10.0.6.tgz#a8aade2de60ba2bce8688e3fa349bad05c7dc1e5" + integrity sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ== 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" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" 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" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== dependencies: escape-string-regexp "^2.0.0" @@ -4852,19 +4822,19 @@ standard-as-callback@^2.1.0: static-eval@2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-2.0.2.tgz#2d1759306b1befa688938454c546b7871f806a42" 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" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== string-length@^4.0.1: version "4.0.2" - resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== dependencies: char-regex "^1.0.2" @@ -4872,134 +4842,125 @@ string-length@^4.0.1: string-template@~0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz" + resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" integrity sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw== -"string-width-cjs@npm:string-width@^4.2.0": +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" 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": +string-width@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 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, string-width@^4.2.0, 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" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: eastasianwidth "^0.2.0" emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string_decoder@^1.1.1, string_decoder@~1.1.1: +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", 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" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 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" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" 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" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" 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" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" 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" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== strip-json-comments@^2.0.0, 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" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 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" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== supports-color@^5.3.0: version "5.5.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 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" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 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" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" 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" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== table@^6.0.4: version "6.8.2" - resolved "https://registry.npmjs.org/table/-/table-6.8.2.tgz" + resolved "https://registry.yarnpkg.com/table/-/table-6.8.2.tgz#c5504ccf201213fa227248bdc8c5569716ac6c58" integrity sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA== dependencies: ajv "^8.0.1" @@ -5010,7 +4971,7 @@ table@^6.0.4: tar-fs@^1.13.0: version "1.16.3" - resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509" integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw== dependencies: chownr "^1.0.1" @@ -5020,7 +4981,7 @@ tar-fs@^1.13.0: tar-stream@^1.1.2: version "1.6.2" - resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== dependencies: bl "^1.0.0" @@ -5033,7 +4994,7 @@ tar-stream@^1.1.2: tar-stream@^2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== dependencies: bl "^4.0.3" @@ -5044,7 +5005,7 @@ tar-stream@^2.2.0: tar@^6.1.11, tar@^6.1.2: version "6.2.1" - resolved "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== dependencies: chownr "^2.0.0" @@ -5056,14 +5017,14 @@ tar@^6.1.11, tar@^6.1.2: tdigest@^0.1.1: version "0.1.2" - resolved "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz" + resolved "https://registry.yarnpkg.com/tdigest/-/tdigest-0.1.2.tgz#96c64bac4ff10746b910b0e23b515794e12faced" integrity sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA== dependencies: bintrees "1.0.2" test-exclude@^6.0.0: version "6.0.0" - resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== dependencies: "@istanbuljs/schema" "^0.1.2" @@ -5072,17 +5033,17 @@ test-exclude@^6.0.0: text-hex@1.0.x: version "1.0.0" - resolved "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" 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" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== thriftrw@^3.5.0: version "3.11.4" - resolved "https://registry.npmjs.org/thriftrw/-/thriftrw-3.11.4.tgz" + resolved "https://registry.yarnpkg.com/thriftrw/-/thriftrw-3.11.4.tgz#84c990ee89e926631c0b475909ada44ee9249870" integrity sha512-UcuBd3eanB3T10nXWRRMwfwoaC6VMk7qe3/5YIWP2Jtw+EbHqJ0p1/K3x8ixiR5dozKSSfcg1W+0e33G1Di3XA== dependencies: bufrw "^1.2.1" @@ -5091,64 +5052,64 @@ thriftrw@^3.5.0: tiny-case@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/tiny-case/-/tiny-case-1.0.3.tgz#d980d66bc72b5d5a9ca86fb7c9ffdb9c898ddd03" integrity sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q== tmp@^0.2.0: version "0.2.3" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== tmpl@1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" 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" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" 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" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" 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" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 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" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" 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" + resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" 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" + resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" 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" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" 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" + resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984" 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" + resolved "https://registry.yarnpkg.com/ts-node-dev/-/ts-node-dev-2.0.0.tgz#bdd53e17ab3b5d822ef519928dc6b4a7e0f13065" integrity sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w== dependencies: chokidar "^3.5.1" @@ -5164,7 +5125,7 @@ ts-node-dev@2.0.0: ts-node@^10.4.0: version "10.9.2" - resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== dependencies: "@cspotcode/source-map-support" "^0.8.0" @@ -5183,7 +5144,7 @@ ts-node@^10.4.0: tsconfig@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz" + resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-7.0.0.tgz#84538875a4dc216e5c4a5432b3a4dec3d54e91b7" integrity sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw== dependencies: "@types/strip-bom" "^3.0.0" @@ -5193,48 +5154,48 @@ tsconfig@^7.0.0: tunnel-agent@^0.6.0: version "0.6.0" - resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" 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" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" 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" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" 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" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== type-fest@^0.21.3: version "0.21.3" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== type-fest@^0.8.1: version "0.8.1" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== type-fest@^2.19.0: version "2.19.0" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" 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" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== dependencies: media-typer "0.3.0" @@ -5242,41 +5203,46 @@ type-is@~1.6.18: typescript@5.4.2: version "5.4.2" - resolved "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372" 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" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.1.tgz#7bb8cc9b3d397e201cf8553336d262544ead829e" 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" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + unique-filename@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-3.0.0.tgz#48ba7a5a16849f5080d26c760c86cf5cf05770ea" 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" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-4.0.0.tgz#6bae6bb16be91351badd24cdce741f892a6532e3" 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" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== unzipper@^0.10.11: version "0.10.14" - resolved "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz" + resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.10.14.tgz#d2b33c977714da0fbc0f82774ad35470a7c962b1" integrity sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g== dependencies: big-integer "^1.6.17" @@ -5290,60 +5256,60 @@ unzipper@^0.10.11: readable-stream "~2.3.6" 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== +update-browserslist-db@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== 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: +uri-js@^4.2.2: version "4.4.1" - resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" 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" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 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" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" 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" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== uuid@^3.0.0: version "3.4.0" - resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== uuid@^8.3.0, uuid@^8.3.2: version "8.3.2" - resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== 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" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" 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" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz#cdada8bec61e15865f05d097c5f4fd30e94dc128" 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== + version "9.3.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== dependencies: "@jridgewell/trace-mapping" "^0.3.12" "@types/istanbul-lib-coverage" "^2.0.1" @@ -5351,54 +5317,54 @@ v8-to-istanbul@^9.0.1: vary@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 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" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" 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" + resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.1.0.tgz#35ccf7b1a0fce87bd8b92a478c9d045785d3bf35" integrity sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA== which@^2.0.1: version "2.0.2" - resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" 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" + resolved "https://registry.yarnpkg.com/which/-/which-4.0.0.tgz#cd60b5e74503a3fbcfbf6cd6b4138a8bae644c1a" 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" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" 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== + version "4.7.1" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.7.1.tgz#52ff1bcfe452ad89991a0aaff9c3b18e7f392569" + integrity sha512-wQCXXVgfv/wUPOfb2x0ruxzwkcZfxcktz6JIMUaPLmcNhO4bZTwA/WtDWK74xV3F2dKu8YadrFv0qhwYjVEwhA== dependencies: - logform "^2.3.2" - readable-stream "^3.6.0" + logform "^2.6.1" + readable-stream "^3.6.2" triple-beam "^1.3.0" winston@3.12.0: version "3.12.0" - resolved "https://registry.npmjs.org/winston/-/winston-3.12.0.tgz" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.12.0.tgz#a5d965a41d3dc31be5408f8c66e927958846c0d0" integrity sha512-OwbxKaOlESDi01mC9rkM0dQqQt2I8DAUMRLZ/HpbwvDXm85IryEHgoogy5fziQy38PntgZsLlhAYHz//UPHZ5w== dependencies: "@colors/colors" "^1.6.0" @@ -5415,31 +5381,22 @@ winston@3.12.0: wmf@~1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/wmf/-/wmf-1.0.2.tgz#7d19d621071a08c2bdc6b7e688a9c435298cc2da" 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" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== word@~0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/word/-/word-0.3.0.tgz" + resolved "https://registry.yarnpkg.com/word/-/word-0.3.0.tgz#8542157e4f8e849f4a363a288992d47612db9961" 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: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" @@ -5448,7 +5405,7 @@ wrap-ansi@^7.0.0: wrap-ansi@^8.1.0: version "8.1.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== dependencies: ansi-styles "^6.1.0" @@ -5457,12 +5414,12 @@ wrap-ansi@^8.1.0: wrappy@1: version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 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" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== dependencies: imurmurhash "^0.1.4" @@ -5470,7 +5427,7 @@ write-file-atomic@^4.0.2: xlsx-populate@1.21.0: version "1.21.0" - resolved "https://registry.npmjs.org/xlsx-populate/-/xlsx-populate-1.21.0.tgz" + resolved "https://registry.yarnpkg.com/xlsx-populate/-/xlsx-populate-1.21.0.tgz#f6cd02401f4cd3d055e81f2b6983ddfeeb60ffe6" integrity sha512-8v2Gm8BehXo6LU7KT802QoXTPkYY1SKk5V8g/UuYZnNB3JzXqud/P99Pxr2yXeKyt+sKlCatmidz6jQNie1hRw== dependencies: cfb "^1.1.3" @@ -5480,7 +5437,7 @@ xlsx-populate@1.21.0: xlsx@*, xlsx@0.18.5: version "0.18.5" - resolved "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz" + resolved "https://registry.yarnpkg.com/xlsx/-/xlsx-0.18.5.tgz#16711b9113c848076b8a177022799ad356eba7d0" integrity sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ== dependencies: adler-32 "~1.3.0" @@ -5493,42 +5450,42 @@ xlsx@*, xlsx@0.18.5: xmlchars@^2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== xorshift@^1.1.1: version "1.2.0" - resolved "https://registry.npmjs.org/xorshift/-/xorshift-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/xorshift/-/xorshift-1.2.0.tgz#30a4cdd8e9f8d09d959ed2a88c42a09c660e8148" integrity sha512-iYgNnGyeeJ4t6U11NpA/QiKy+PXn5Aa3Azg5qkwIFz1tBLllQrjjsk9yzD7IAK0naNU4JxdeDgqW9ov4u/hc4g== xtend@^4.0.0, xtend@~4.0.0: version "4.0.2" - resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" 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" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" 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" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== yallist@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" 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" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" 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" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== dependencies: cliui "^8.0.1" @@ -5541,17 +5498,17 @@ yargs@^17.3.1: yn@3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" 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" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" 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" + resolved "https://registry.yarnpkg.com/yup/-/yup-1.4.0.tgz#898dcd660f9fb97c41f181839d3d65c3ee15a43e" integrity sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg== dependencies: property-expr "^2.0.5" @@ -5561,7 +5518,7 @@ yup@1.4.0: zip-stream@^4.1.0: version "4.1.1" - resolved "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.1.1.tgz#1337fe974dbaffd2fa9a1ba09662a66932bd7135" integrity sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ== dependencies: archiver-utils "^3.0.4" diff --git a/health-services/project/CHANGELOG.md b/health-services/project/CHANGELOG.md index 7865206457c..c995b81daaf 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.6 - 2025-01-27 +- Added isAncestorProjectId param for search projects API to support search projects with ancestor project id as well + ## 1.1.5 - 2024-08-07 - Added UserAction functionality with support for Location capture. @@ -13,6 +16,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/project/pom.xml b/health-services/project/pom.xml index fd0b688dcc3..2f5e99a45ab 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -5,7 +5,7 @@ project jar project - 1.1.5 + 1.1.6 17 ${java.version} @@ -45,12 +45,12 @@ org.egov.common health-services-common - 1.0.18-SNAPSHOT + 1.0.20-dev-SNAPSHOT org.egov.common health-services-models - 1.0.21-SNAPSHOT + 1.0.25-dev-SNAPSHOT compile @@ -114,6 +114,12 @@ 2.13.0 test + + org.egov.services + digit-models + 1.0.0-SNAPSHOT + compile + diff --git a/health-services/project/src/main/java/org/egov/project/repository/ProjectFacilityRepository.java b/health-services/project/src/main/java/org/egov/project/repository/ProjectFacilityRepository.java index d602f809b15..219a38458ec 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/ProjectFacilityRepository.java +++ b/health-services/project/src/main/java/org/egov/project/repository/ProjectFacilityRepository.java @@ -1,9 +1,13 @@ package org.egov.project.repository; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; 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.ProjectFacility; +import org.egov.common.models.project.ProjectFacilitySearch; import org.egov.common.producer.Producer; import org.egov.project.repository.rowmapper.ProjectFacilityRowMapper; import org.springframework.beans.factory.annotation.Autowired; @@ -11,15 +15,16 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; +import java.util.List; import java.util.Optional; @Repository @Slf4j public class ProjectFacilityRepository extends GenericRepository { @Autowired public ProjectFacilityRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, - RedisTemplate redisTemplate, - SelectQueryBuilder selectQueryBuilder, ProjectFacilityRowMapper projectFacilityRowMapper) { + RedisTemplate redisTemplate, + SelectQueryBuilder selectQueryBuilder, ProjectFacilityRowMapper projectFacilityRowMapper) { super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, projectFacilityRowMapper, Optional.of("project_facility")); } -} +} \ No newline at end of file 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 ae7b4c9994b..31bd571cb77 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 @@ -69,37 +69,44 @@ public ProjectRepository(Producer producer, NamedParameterJdbcTemplate namedPara } - public List getProjects(ProjectRequest project, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted, Boolean includeAncestors, Boolean includeDescendants, Long createdFrom, Long createdTo) { + /** + * @param isAncestorProjectId When true, treats the project IDs in the ProjectRequest as ancestor project IDs + */ + public List getProjects(ProjectRequest project, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted, Boolean includeAncestors, Boolean includeDescendants, Long createdFrom, Long createdTo, boolean isAncestorProjectId) { //Fetch Projects based on search criteria - List projects = getProjectsBasedOnSearchCriteria(project.getProjects(), limit, offset, tenantId, lastChangedSince, includeDeleted, createdFrom, createdTo); + List projects = getProjectsBasedOnSearchCriteria(project.getProjects(), limit, offset, tenantId, lastChangedSince, includeDeleted, createdFrom, createdTo, isAncestorProjectId); 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 (includeAncestors) { - ancestors = getProjectAncestors(projects); - if (ancestors != null && !ancestors.isEmpty()) { - List ancestorProjectIds = ancestors.stream().map(Project :: getId).collect(Collectors.toList()); - projectIds.addAll(ancestorProjectIds); + List targets = new ArrayList<>(); + List documents = new ArrayList<>(); + if(!projectIds.isEmpty()) { + //Get Project ancestors if includeAncestors flag is true + if (includeAncestors) { + 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 (includeDescendants) { - descendants = getProjectDescendants(projects); - if (descendants != null && !descendants.isEmpty()) { - List descendantsProjectIds = descendants.stream().map(Project :: getId).collect(Collectors.toList()); - projectIds.addAll(descendantsProjectIds); + //Get Project descendants if includeDescendants flag is true + if (includeDescendants) { + 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 targets based on Project Ids + targets = getTargetsBasedOnProjectIds(projectIds); - //Fetch documents based on Project Ids - List documents = getDocumentsBasedOnProjectIds(projectIds); + //Fetch documents based on Project Ids + documents = getDocumentsBasedOnProjectIds(projectIds); + } //Construct Project Objects with fetched projects, targets and documents using Project id return buildProjectSearchResult(projects, targets, documents, ancestors, descendants); @@ -114,28 +121,32 @@ public List getProjects(@NotNull @Valid ProjectSearch projectSearch, @V 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); + List targets = new ArrayList<>(); + List documents = new ArrayList<>(); + if(!projectIds.isEmpty()) { + //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).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); + //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).toList(); + projectIds.addAll(descendantsProjectIds); + } } - } - //Fetch targets based on Project Ids - List targets = getTargetsBasedOnProjectIds(projectIds); + //Fetch targets based on Project Ids + targets = getTargetsBasedOnProjectIds(projectIds); - //Fetch documents based on Project Ids - List documents = getDocumentsBasedOnProjectIds(projectIds); + //Fetch documents based on Project Ids + documents = getDocumentsBasedOnProjectIds(projectIds); + } //Construct Project Objects with fetched projects, targets and documents using Project id return buildProjectSearchResult(projects, targets, documents, ancestors, descendants); @@ -151,9 +162,9 @@ private List getProjectsBasedOnV2SearchCriteria(@NotNull @Valid Project } /* 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) { + private List getProjectsBasedOnSearchCriteria(List projectsRequest, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted, Long createdFrom, Long createdTo, boolean isAncestorProjectId) { List preparedStmtList = new ArrayList<>(); - String query = queryBuilder.getProjectSearchQuery(projectsRequest, limit, offset, tenantId, lastChangedSince, includeDeleted, createdFrom, createdTo, preparedStmtList, false); + String query = queryBuilder.getProjectSearchQuery(projectsRequest, limit, offset, tenantId, lastChangedSince, includeDeleted, createdFrom, createdTo, isAncestorProjectId, preparedStmtList, false); List projects = jdbcTemplate.query(query, addressRowMapper, preparedStmtList.toArray()); log.info("Fetched project list based on given search criteria"); @@ -339,9 +350,9 @@ private void addDescendantsToProjectSearchResult(Project project, List * query build at the run time) * @return */ - public Integer getProjectCount(ProjectRequest project, String tenantId, Long lastChangedSince, Boolean includeDeleted, Long createdFrom, Long createdTo) { + public Integer getProjectCount(ProjectRequest project, String tenantId, Long lastChangedSince, Boolean includeDeleted, Long createdFrom, Long createdTo, boolean isAncestorProjectId) { List preparedStatement = new ArrayList<>(); - String query = queryBuilder.getSearchCountQueryString(project.getProjects(), tenantId, lastChangedSince, includeDeleted, createdFrom, createdTo, preparedStatement); + String query = queryBuilder.getSearchCountQueryString(project.getProjects(), tenantId, lastChangedSince, includeDeleted, createdFrom, createdTo, isAncestorProjectId, preparedStatement); if (query == null) return 0; 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 4b3aeda7bac..bce83d7cc5d 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 @@ -46,8 +46,11 @@ public class ProjectAddressQueryBuilder { "left join project_address addr " + "on prj.id = addr.projectId ";; - /* Constructs project search query based on conditions */ - public String getProjectSearchQuery(List projects, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted, Long createdFrom, Long createdTo, List preparedStmtList, boolean isCountQuery) { + /** + * Constructs project search query based on conditions + * @param isAncestorProjectId if set to true, project id in the projects would be considered as ancestor project id. + */ + public String getProjectSearchQuery(List projects, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted, Long createdFrom, Long createdTo, boolean isAncestorProjectId, List preparedStmtList, boolean isCountQuery) { //This uses a ternary operator to choose between PROJECTS_COUNT_QUERY or FETCH_PROJECT_ADDRESS_QUERY based on the value of isCountQuery. String query = isCountQuery ? PROJECTS_COUNT_QUERY : FETCH_PROJECT_ADDRESS_QUERY; StringBuilder queryBuilder = new StringBuilder(query); @@ -69,7 +72,16 @@ public String getProjectSearchQuery(List projects, Integer limit, Integ } } - if (StringUtils.isNotBlank(project.getId())) { + /* + * If isAncestorProjectId is set to true, Then either id equals to project id or projectHierarchy + * should have id of the project + */ + if (isAncestorProjectId && StringUtils.isNotBlank(project.getId())) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" ( prj.projectHierarchy LIKE ? OR prj.id =? ) "); + preparedStmtList.add('%' + project.getId() + '%'); + preparedStmtList.add(project.getId()); + } else if (StringUtils.isNotBlank(project.getId())) { addClauseIfRequired(preparedStmtList, queryBuilder); queryBuilder.append(" prj.id =? "); preparedStmtList.add(project.getId()); @@ -379,8 +391,8 @@ public String getProjectDescendantsSearchQueryBasedOnIds(List projectIds } /* Returns query to get total projects count based on project search params */ - public String getSearchCountQueryString(List projects, String tenantId, Long lastChangedSince, Boolean includeDeleted, Long createdFrom, Long createdTo, List preparedStatement) { - String query = getProjectSearchQuery(projects, config.getMaxLimit(), config.getDefaultOffset(), tenantId, lastChangedSince, includeDeleted, createdFrom, createdTo, preparedStatement, true); + public String getSearchCountQueryString(List projects, String tenantId, Long lastChangedSince, Boolean includeDeleted, Long createdFrom, Long createdTo, boolean isAncestorProjectId, List preparedStatement) { + String query = getProjectSearchQuery(projects, config.getMaxLimit(), config.getDefaultOffset(), tenantId, lastChangedSince, includeDeleted, createdFrom, createdTo, isAncestorProjectId, preparedStatement, true); return query; } 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 b9d3f814d7c..b2fcfb5672a 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 @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.project.Document; import org.egov.tracer.model.CustomException; import org.postgresql.util.PGobject; 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 index b9ea8babec8..a5a8da51b09 100644 --- 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 @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.UserActionEnum; 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 fa5d72c5dc7..b4cd46201b3 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 @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.project.Address; import org.egov.common.models.project.AddressType; import org.egov.common.models.project.Project; 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 c79c91ed161..663ada6310f 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 @@ -2,7 +2,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectBeneficiary; import org.springframework.jdbc.core.RowMapper; 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 d6433f36db6..3d622db4a42 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 @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectFacility; import org.springframework.jdbc.core.RowMapper; 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..bd6aa793bb6 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 @@ -1,7 +1,7 @@ package org.egov.project.repository.rowmapper; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.project.ProjectProductVariant; import org.egov.common.models.project.ProjectResource; import org.springframework.beans.factory.annotation.Autowired; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectRowMapper.java index b8625274dfc..a4e1193eed2 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectRowMapper.java @@ -1,6 +1,6 @@ package org.egov.project.repository.rowmapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.project.Project; 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/ProjectStaffRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java index a0ff3d24bcf..169bdc99d40 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 @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectStaff; import org.springframework.jdbc.core.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 ccff648bd41..406a7419c54 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 @@ -2,7 +2,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.Address; import org.egov.common.models.project.AddressType; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TargetRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TargetRowMapper.java index f9b352a69b4..f8a3b22fbc5 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TargetRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TargetRowMapper.java @@ -1,6 +1,7 @@ package org.egov.project.repository.rowmapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; +import org.egov.common.models.project.BeneficiaryType; import org.egov.common.models.project.Target; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.ResultSetExtractor; @@ -40,7 +41,7 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessExc Target target = Target.builder() .id(target_id) .projectid(target_projectId) - .beneficiaryType(target_beneficiaryType) + .beneficiaryType(BeneficiaryType.fromValue(target_beneficiaryType)) .totalNo(target_totalNo) .targetNo(target_targetNo) .isDeleted(target_isDeleted) 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 87cab062d9c..1187e1692e6 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 @@ -2,7 +2,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.TaskResource; import org.springframework.jdbc.core.RowMapper; 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 index 8a63f0f3c99..57c992ae154 100644 --- 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 @@ -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.contract.models.AuditDetails; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.UserActionEnum; 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 f7628318789..9e5e47675bb 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,9 +1,16 @@ 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.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectFacility; import org.egov.common.models.project.ProjectFacilityBulkRequest; import org.egov.common.models.project.ProjectFacilityRequest; @@ -27,12 +34,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -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.handleErrors; import static org.egov.common.utils.CommonUtils.havingTenantId; import static org.egov.common.utils.CommonUtils.includeDeleted; @@ -214,27 +215,27 @@ private Tuple, Map> validat return new Tuple<>(validEntities, errorDetailsMap); } - public List search(ProjectFacilitySearchRequest projectFacilitySearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { + public SearchResponse search(ProjectFacilitySearchRequest projectFacilitySearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { log.info("received request to search project facility"); if (isSearchByIdOnly(projectFacilitySearchRequest.getProjectFacility())) { log.info("searching project facility by id"); List ids = projectFacilitySearchRequest.getProjectFacility().getId(); log.info("fetching project facility with ids: {}", ids); - return projectFacilityRepository.findById(ids, includeDeleted).stream() + List projectfacilities = projectFacilityRepository.findById(ids, includeDeleted).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); + return SearchResponse.builder().response(projectfacilities).build(); } log.info("searching project facility using criteria"); - return projectFacilityRepository.find(projectFacilitySearchRequest.getProjectFacility(), + return projectFacilityRepository.findWithCount(projectFacilitySearchRequest.getProjectFacility(), limit, offset, tenantId, lastChangedSince, includeDeleted); } - } 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 660efbd4814..8f8c2555947 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 @@ -5,6 +5,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.project.ProjectResource; import org.egov.common.models.project.ProjectResourceBulkRequest; import org.egov.common.models.project.ProjectResourceRequest; @@ -182,27 +183,28 @@ public List delete(ProjectResourceBulkRequest request, boolean } - public List search(ProjectResourceSearchRequest request, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws QueryBuilderException { + public SearchResponse search(ProjectResourceSearchRequest request, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws QueryBuilderException { String idFieldName = getIdFieldName(request.getProjectResource()); if (isSearchByIdOnly(request.getProjectResource(), idFieldName)) { List ids = (List) ReflectionUtils.invokeMethod(getIdMethod((Collections .singletonList(request.getProjectResource()))), request.getProjectResource()); - return projectResourceRepository.findById(ids, includeDeleted, idFieldName).stream() + List projectResources = projectResourceRepository.findById(ids, includeDeleted, idFieldName).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); + return SearchResponse.builder().response(projectResources).build(); } log.info("completed search method for project resource"); - return projectResourceRepository.find(request.getProjectResource(), + return projectResourceRepository.findWithCount(request.getProjectResource(), limit, offset, tenantId, lastChangedSince, includeDeleted); } } 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 56e2665792a..349248e1ac6 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,7 +1,7 @@ package org.egov.project.service; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import jakarta.validation.Valid; import java.util.Map; import lombok.extern.slf4j.Slf4j; @@ -79,6 +79,11 @@ public ProjectRequest createProject(ProjectRequest projectRequest) { return projectRequest; } + /** + * Search for projects based on various criteria + * @param isAncestorProjectId When true, treats the project IDs in the search criteria as ancestor project IDs + * and returns all projects (including children) under these ancestors + */ public List searchProject( ProjectRequest project, Integer limit, @@ -89,7 +94,8 @@ public List searchProject( Boolean includeAncestors, Boolean includeDescendants, Long createdFrom, - Long createdTo + Long createdTo, + boolean isAncestorProjectId ) { projectValidator.validateSearchProjectRequest(project, limit, offset, tenantId, createdFrom, createdTo); List projects = projectRepository.getProjects( @@ -102,7 +108,8 @@ public List searchProject( includeAncestors, includeDescendants, createdFrom, - createdTo + createdTo, + isAncestorProjectId ); return projects; } @@ -125,7 +132,7 @@ public ProjectRequest updateProject(ProjectRequest 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 + request.getProjects().get(0).getTenantId(), null, false, false, false, null, null, false ); log.info("Fetched projects for update request"); @@ -280,7 +287,8 @@ private void checkAndEnrichCascadingProjectDates(ProjectRequest request, Project true, true, null, - null + null, + false ); /* @@ -301,7 +309,7 @@ private List getParentProjects(ProjectRequest projectRequest) { List parentProjects = null; List projectsForSearchRequest = projectRequest.getProjects().stream().filter(p -> StringUtils.isNotBlank(p.getParent())).collect(Collectors.toList()); if (projectsForSearchRequest.size() > 0) { - parentProjects = searchProject(getSearchProjectRequest(projectsForSearchRequest, projectRequest.getRequestInfo(), true), projectConfiguration.getMaxLimit(), projectConfiguration.getDefaultOffset(), projectRequest.getProjects().get(0).getTenantId(), null, false, false, false, null, null); + parentProjects = searchProject(getSearchProjectRequest(projectsForSearchRequest, projectRequest.getRequestInfo(), true), projectConfiguration.getMaxLimit(), projectConfiguration.getDefaultOffset(), projectRequest.getProjects().get(0).getTenantId(), null, false, false, false, null, null, false); } log.info("Fetched parent projects from DB"); return parentProjects; @@ -329,8 +337,8 @@ private ProjectRequest getSearchProjectRequest(List projects, RequestIn /** * @return Count of List of matching projects */ - 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(ProjectRequest project, String tenantId, Long lastChangedSince, Boolean includeDeleted, Long createdFrom, Long createdTo, boolean isAncestorProjectId) { + return projectRepository.getProjectCount(project, tenantId, lastChangedSince, includeDeleted, createdFrom, createdTo, isAncestorProjectId); } 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 c600537a74e..d172b96263f 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 @@ -4,6 +4,7 @@ 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; import org.egov.common.models.project.ProjectStaff; import org.egov.common.models.project.ProjectStaffBulkRequest; import org.egov.common.models.project.ProjectStaffRequest; @@ -28,9 +29,7 @@ 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; @@ -224,26 +223,27 @@ private Tuple, Map> validate(List return new Tuple<>(validEntities, errorDetailsMap); } - public List search(ProjectStaffSearchRequest projectStaffSearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { + public SearchResponse search(ProjectStaffSearchRequest projectStaffSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { log.info("received request to search project staff"); if (isSearchByIdOnly(projectStaffSearchRequest.getProjectStaff())) { log.info("searching project staff by id"); List ids = projectStaffSearchRequest.getProjectStaff().getId(); log.info("fetching project staff with ids: {}", ids); - return projectStaffRepository.findById(ids, includeDeleted).stream() + List projectStaffs = projectStaffRepository.findById(ids, includeDeleted).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); + return SearchResponse.builder().response(projectStaffs).build(); } log.info("searching project staff using criteria"); - return projectStaffRepository.find(projectStaffSearchRequest.getProjectStaff(), + return projectStaffRepository.findWithCount(projectStaffSearchRequest.getProjectStaff(), limit, offset, tenantId, lastChangedSince, includeDeleted); } 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 2bd670f589f..6497beb4d53 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 @@ -4,7 +4,7 @@ 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 org.egov.common.contract.models.AuditDetails; import java.util.Map; import java.util.ArrayList; import lombok.extern.slf4j.Slf4j; 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 db974db9be9..97bdaecc500 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 @@ -4,7 +4,7 @@ import java.util.Map; import java.util.stream.Collectors; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.project.Address; import org.egov.common.models.project.Task; 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 3a0a08d31ea..2ac778f4891 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 @@ -1,26 +1,26 @@ package org.egov.project.util; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.JsonPath; -import digit.models.coremodels.RequestInfoWrapper; 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.models.RequestInfoWrapper; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.tracer.model.CustomException; +import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - @Component @Slf4j 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 4de61e5ab79..be006ad385d 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 @@ -5,10 +5,10 @@ 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; -import digit.models.coremodels.mdms.ModuleDetail; +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 lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; 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 7d750e8d984..8c9b810eecc 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 @@ -3,7 +3,7 @@ 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 org.egov.common.contract.models.AuditDetails; import java.util.Iterator; import java.util.List; import java.util.Map; 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 19c8454d63a..1d6a693e0c6 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 @@ -3,10 +3,11 @@ 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 org.egov.common.models.project.*; +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 lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; @@ -20,10 +21,6 @@ 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.BeneficiaryBulkRequest; -import org.egov.common.models.project.Project; -import org.egov.common.models.project.ProjectBeneficiary; -import org.egov.common.models.project.ProjectType; import org.egov.common.service.MdmsService; import org.egov.common.validator.Validator; import org.egov.project.config.ProjectConfiguration; @@ -103,11 +100,11 @@ public Map> validate(BeneficiaryBulkRequest bene Map projectMap = getIdToObjMap(existingProjects); log.info("creating beneficiaryType map"); - Map> beneficiaryTypeMap = validProjectBeneficiaries.stream() + Map> beneficiaryTypeMap = validProjectBeneficiaries.stream() .collect(Collectors.groupingBy(b -> projectTypeMap.get(projectMap.get(b .getProjectId()).getProjectTypeId()).getBeneficiaryType())); - for (Map.Entry> entry : beneficiaryTypeMap.entrySet()) { + for (Map.Entry> entry : beneficiaryTypeMap.entrySet()) { log.info("fetch the beneficiaries for type {}", entry.getKey()); searchBeneficiary(entry.getKey(), entry.getValue(), beneficiaryBulkRequest.getRequestInfo(), tenantId, errorDetailsMap); @@ -116,18 +113,18 @@ public Map> validate(BeneficiaryBulkRequest bene return errorDetailsMap; } - private void searchBeneficiary(String beneficiaryType, List beneficiaryList, + private void searchBeneficiary(BeneficiaryType beneficiaryType, List beneficiaryList, RequestInfo requestInfo, String tenantId, Map> errorDetailsMap) { switch (beneficiaryType) { - case "HOUSEHOLD": + case HOUSEHOLD: searchHouseholdBeneficiary(beneficiaryList, requestInfo, tenantId, errorDetailsMap); break; - case "INDIVIDUAL": + case INDIVIDUAL: searchIndividualBeneficiary(beneficiaryList, requestInfo, tenantId, errorDetailsMap); break; default: - throw new CustomException("INVALID_BENEFICIARY_TYPE", beneficiaryType); + throw new CustomException("INVALID_BENEFICIARY_TYPE", beneficiaryType.name()); } } @@ -333,4 +330,4 @@ private MdmsCriteriaReq getMdmsRequest(RequestInfo requestInfo, String tenantId, mdmsCriteriaReq.setRequestInfo(requestInfo); return mdmsCriteriaReq; } -} +} \ No newline at end of file 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 7491e024ec3..5aecbe1a6c9 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 @@ -1,9 +1,15 @@ package org.egov.project.validator.staff; -import digit.models.coremodels.UserSearchRequest; +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.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.User; +import org.egov.common.contract.user.UserSearchRequest; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; import org.egov.common.models.individual.Individual; @@ -18,12 +24,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.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; @@ -112,4 +112,4 @@ public Map> validate(ProjectStaffBulkRequest request) } return errorDetailsMap; } -} +} \ No newline at end of file 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 e3be161fabb..44169bf63e3 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 @@ -8,10 +8,6 @@ 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; @@ -22,6 +18,10 @@ import org.egov.common.service.MdmsService; import org.egov.common.utils.CommonUtils; import org.egov.common.validator.Validator; +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.project.config.ProjectConfiguration; import org.egov.tracer.model.CustomException; import org.springframework.core.annotation.Order; @@ -234,4 +234,4 @@ private MdmsCriteriaReq getMdmsRequest(RequestInfo requestInfo, String tenantId, mdmsCriteriaReq.setRequestInfo(requestInfo); return mdmsCriteriaReq; } -} +} \ No newline at end of file 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 1b74b7ab1d7..49017853794 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 @@ -220,7 +220,7 @@ 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( + SearchResponse searchResponse = projectFacilityService.search( projectFacilitySearchRequest, urlParams.getLimit(), urlParams.getOffset(), @@ -229,7 +229,8 @@ public ResponseEntity projectFacilityV2SearchPost( urlParams.getIncludeDeleted() ); ProjectFacilityBulkResponse response = ProjectFacilityBulkResponse.builder() - .projectFacilities(projectFacilities) + .projectFacilities(searchResponse.getResponse()) + .totalCount(searchResponse.getTotalCount()) .responseInfo(ResponseInfoFactory .createResponseInfo(projectFacilitySearchRequest.getRequestInfo(), true)) .build(); @@ -310,7 +311,7 @@ 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( + SearchResponse searchResponse = projectStaffService.search( projectStaffSearchRequest, urlParams.getLimit(), urlParams.getOffset(), @@ -319,7 +320,8 @@ public ResponseEntity projectStaffV1SearchPost( urlParams.getIncludeDeleted() ); ProjectStaffBulkResponse response = ProjectStaffBulkResponse.builder() - .projectStaff(projectStaffList) + .projectStaff(searchResponse.getResponse()) + .totalCount(searchResponse.getTotalCount()) .responseInfo(ResponseInfoFactory .createResponseInfo(projectStaffSearchRequest.getRequestInfo(), true)) .build(); @@ -484,7 +486,8 @@ public ResponseEntity searchProject( @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 + @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, + @ApiParam(value = "Used in project search API to specify if response should be one which is in the preceding hierarchy of matched projects.") @Valid @RequestParam(value = "isAncestorProjectId", required = false, defaultValue = "false") boolean isAncestorProjectId ) { List projects = projectService.searchProject( project, @@ -496,10 +499,11 @@ public ResponseEntity searchProject( includeAncestors, includeDescendants, createdFrom, - createdTo + createdTo, + isAncestorProjectId ); ResponseInfo responseInfo = ResponseInfoFactory.createResponseInfo(project.getRequestInfo(), true); - Integer count = projectService.countAllProjects(project, tenantId, lastChangedSince, includeDeleted, createdFrom, createdTo); + Integer count = projectService.countAllProjects(project, tenantId, lastChangedSince, includeDeleted, createdFrom, createdTo, isAncestorProjectId); ProjectResponse projectResponse = ProjectResponse.builder().responseInfo(responseInfo).project(projects).totalCount(count).build(); return new ResponseEntity(projectResponse, HttpStatus.OK); } 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 6f71ea7ef93..ef0522cfbf0 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 @@ -7,6 +7,7 @@ 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.SearchResponse; import org.egov.common.models.core.URLParams; import org.egov.common.models.project.ProjectResource; import org.egov.common.models.project.ProjectResourceBulkRequest; @@ -75,7 +76,7 @@ public ResponseEntity resourceV1SearchPost( @ApiParam(value = "Search linkage of Project and resource.", required = true) @Valid @RequestBody ProjectResourceSearchRequest projectResourceSearchRequest ) throws QueryBuilderException { - List projectResource = projectResourceService.search( + SearchResponse searchResponse = projectResourceService.search( projectResourceSearchRequest, urlParams.getLimit(), urlParams.getOffset(), @@ -84,7 +85,10 @@ public ResponseEntity resourceV1SearchPost( urlParams.getIncludeDeleted() ); ProjectResourceBulkResponse response = ProjectResourceBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(projectResourceSearchRequest.getRequestInfo(), true)).projectResource(projectResource).build(); + .createResponseInfo(projectResourceSearchRequest.getRequestInfo(), true)) + .projectResource(searchResponse.getResponse()) + .totalCount(searchResponse.getTotalCount()) + .build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/project/src/main/resources/application.properties b/health-services/project/src/main/resources/application.properties index 71af8eab0d3..e27c6d18403 100644 --- a/health-services/project/src/main/resources/application.properties +++ b/health-services/project/src/main/resources/application.properties @@ -184,3 +184,4 @@ project.task.no.resource.validation.status=ADMINISTRATION_FAILED, BENEFICIARY_RE #---------Attendance Feature ------------# project.attendance.feature.enabled=true + diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceCreateTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceCreateTest.java index 93740830a51..fccdb5d0d1d 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceCreateTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceCreateTest.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.mdms.MdmsCriteriaReq; +import org.egov.mdms.model.MdmsCriteriaReq; import org.apache.commons.io.IOUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; 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 805fba5c474..e4675e45bc2 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 @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.mdms.MdmsCriteriaReq; +import org.egov.mdms.model.MdmsCriteriaReq; import org.apache.commons.io.IOUtils; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.core.SearchResponse; 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 6eed8465ca5..85fd9f4e71b 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 @@ -1,6 +1,7 @@ package org.egov.project.service; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectFacility; import org.egov.project.helper.ProjectFacilityTestBuilder; import org.egov.project.repository.ProjectFacilityRepository; @@ -46,9 +47,9 @@ void setUp() { @Test @DisplayName("should not raise exception if no search results are found") void shouldNotRaiseExceptionIfNoProjectFacilityFound() throws Exception { - when(projectFacilityRepository.find(any(ProjectFacilitySearch.class), any(Integer.class), + when(projectFacilityRepository.findWithCount(any(ProjectFacilitySearch.class), any(Integer.class), any(Integer.class), any(String.class), eq(null), any(Boolean.class))) - .thenReturn(Collections.emptyList()); + .thenReturn(SearchResponse.builder().response(Collections.emptyList()).build()); ProjectFacilitySearch projectFacilitySearch = ProjectFacilitySearch.builder() .id(Collections.singletonList("ID101")).facilityId(Collections.singletonList("some-facility-id")).build(); ProjectFacilitySearchRequest projectFacilitySearchRequest = ProjectFacilitySearchRequest.builder() @@ -77,8 +78,9 @@ void shouldNotRaiseExceptionIfNoProjectFacilityFoundForSearchById() { @Test @DisplayName("should return project facility if search criteria is matched") void shouldReturnProjectFacilityIfSearchCriteriaIsMatched() throws Exception { - when(projectFacilityRepository.find(any(ProjectFacilitySearch.class), any(Integer.class), - any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(projectFacilities); + when(projectFacilityRepository.findWithCount(any(ProjectFacilitySearch.class), any(Integer.class), + any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(SearchResponse.builder() + .response(projectFacilities).build()); projectFacilities.add(ProjectFacilityTestBuilder.builder().withId().withId().withAuditDetails().build()); ProjectFacilitySearch projectFacilitySearch = ProjectFacilitySearch.builder() .id(Collections.singletonList("ID101")).projectId(Collections.singletonList("some-projectId")).build(); @@ -87,7 +89,7 @@ void shouldReturnProjectFacilityIfSearchCriteriaIsMatched() throws Exception { .withCompleteRequestInfo().build()).build(); List projectFacilities = projectFacilityService.search(projectFacilitySearchRequest, - 10, 0, "default", null, false); + 10, 0, "default", null, false).getResponse(); assertEquals(1, projectFacilities.size()); } @@ -104,7 +106,7 @@ void shouldReturnFromCacheIfSearchCriteriaHasIdOnly() throws Exception { when(projectFacilityRepository.findById(anyList(), anyBoolean())).thenReturn(projectFacilities); List projectFacilities = projectFacilityService.search(projectFacilitySearchRequest, - 10, 0, null, null, true); + 10, 0, null, null, true).getResponse(); assertEquals(1, projectFacilities.size()); } 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 36aa7100f8d..f14fa8f9a9e 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 @@ -1,6 +1,7 @@ package org.egov.project.service; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectStaff; import org.egov.project.helper.ProjectStaffTestBuilder; import org.egov.project.repository.ProjectStaffRepository; @@ -46,9 +47,9 @@ void setUp() { @Test @DisplayName("should not raise exception if no search results are found") void shouldNotRaiseExceptionIfNoProjectStaffFound() throws Exception { - when(projectStaffRepository.find(any(ProjectStaffSearch.class), any(Integer.class), + when(projectStaffRepository.findWithCount(any(ProjectStaffSearch.class), any(Integer.class), any(Integer.class), any(String.class), eq(null), any(Boolean.class))) - .thenReturn(Collections.emptyList()); + .thenReturn(SearchResponse.builder().response(Collections.emptyList()).build()); ProjectStaffSearch projectStaffSearch = ProjectStaffSearch.builder() .id(Collections.singletonList("ID101")).staffId(Collections.singletonList("some-user-id")).build(); ProjectStaffSearchRequest projectStaffSearchRequest = ProjectStaffSearchRequest.builder() @@ -75,15 +76,15 @@ void shouldNotRaiseExceptionIfNoProjectStaffFoundForSearchById() { @Test @DisplayName("should return project staff if search criteria is matched") 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); + when(projectStaffRepository.findWithCount(any(ProjectStaffSearch.class), any(Integer.class), + any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(SearchResponse.builder().response(projectStaffs).build()); projectStaffs.add(ProjectStaffTestBuilder.builder().withId().withId().withAuditDetails().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(); - List projectStaffs = projectStaffService.search(projectStaffSearchRequest, 10, 0, "default", null, false); + List projectStaffs = projectStaffService.search(projectStaffSearchRequest, 10, 0, "default", null, false).getResponse(); assertEquals(1, projectStaffs.size()); } @@ -100,7 +101,7 @@ void shouldReturnFromCacheIfSearchCriteriaHasIdOnly() throws Exception { when(projectStaffRepository.findById(anyList(), anyBoolean())).thenReturn(projectStaffs); List projectStaffs = projectStaffService.search(projectStaffSearchRequest, - 10, 0, null, null, true); + 10, 0, null, null, true).getResponse(); assertEquals(1, projectStaffs.size()); } 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 e6a97cf70c8..fe6a8e402db 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 @@ -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.ProjectFacility; import org.egov.common.models.project.ProjectFacilityBulkRequest; import org.egov.common.models.project.ProjectFacilityBulkResponse; @@ -193,8 +194,9 @@ void shouldAcceptSearchRequestAndReturnProjectFacility() throws Exception { any(Integer.class), any(String.class), any(Long.class), - any(Boolean.class))).thenReturn(Arrays.asList(ProjectFacilityTestBuilder.builder() - .withId().withAuditDetails().build())); + any(Boolean.class))).thenReturn(SearchResponse.builder() + .response(Arrays.asList(ProjectFacilityTestBuilder.builder() + .withId().withAuditDetails().build())).build()); final MvcResult result = mockMvc.perform(post( "/facility/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") 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 1e1b5409485..2147e98e460 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 @@ -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.ProjectStaff; import org.egov.common.models.project.ProjectStaffBulkResponse; import org.egov.common.models.project.ProjectStaffRequest; @@ -175,7 +176,7 @@ void shouldAcceptSearchRequestAndReturnProjectStaff() throws Exception { any(Integer.class), any(String.class), any(Long.class), - any(Boolean.class))).thenReturn(Arrays.asList(ProjectStaffTestBuilder.builder().withId().withAuditDetails().build())); + any(Boolean.class))).thenReturn(SearchResponse.builder().response(Arrays.asList(ProjectStaffTestBuilder.builder().withId().withAuditDetails().build())).build()); final MvcResult result = mockMvc.perform(post( "/staff/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") 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/referralmanagement/pom.xml b/health-services/referralmanagement/pom.xml index b9d85ad8269..4bf32a9765a 100644 --- a/health-services/referralmanagement/pom.xml +++ b/health-services/referralmanagement/pom.xml @@ -46,12 +46,12 @@ org.egov.common health-services-common - 1.0.18-SNAPSHOT + 1.0.20-dev-SNAPSHOT org.egov.common health-services-models - 1.0.20-SNAPSHOT + 1.0.23-dev-SNAPSHOT compile 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 d2d43634030..0fee8b9d853 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 @@ -12,6 +12,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.referralmanagement.hfreferral.HFReferral; import org.egov.common.models.referralmanagement.hfreferral.HFReferralSearch; import org.egov.common.producer.Producer; @@ -23,6 +24,7 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; +import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; import static org.egov.common.utils.CommonUtils.getIdMethod; /** @@ -66,7 +68,7 @@ protected HFReferralRepository(Producer producer, NamedParameterJdbcTemplate nam * @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, + public SearchResponse 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"; @@ -96,16 +98,21 @@ public List find(HFReferralSearch searchObject, Integer limit, Integ } // Add ORDER BY, LIMIT, and OFFSET clauses to the query. - query = query + "ORDER BY hf.createdtime DESC LIMIT :limit OFFSET :offset"; + query = query + "ORDER BY hf.createdtime DESC"; paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); paramsMap.put("lastModifiedTime", lastChangedSince); + + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + + query += " LIMIT :limit OFFSET :offset"; 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; + + return SearchResponse.builder().response(hfReferralList).totalCount(totalCount).build(); } /** @@ -116,7 +123,7 @@ public List find(HFReferralSearch searchObject, Integer limit, Integ * @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) { + public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { // Find objects in the cache based on the provided IDs. List objFound = findInCache(ids); if (!includeDeleted) { @@ -134,7 +141,7 @@ public List findById(List ids, Boolean includeDeleted, Strin // If no IDs are remaining, return the objects found in the cache. if (ids.isEmpty()) { - return objFound; + return SearchResponse.builder().response(objFound).build(); } } @@ -154,6 +161,6 @@ public List findById(List ids, Boolean includeDeleted, Strin // Add the retrieved entities to the cache. objFound.addAll(hfReferralList); putInCache(objFound); - return objFound; + return SearchResponse.builder().response(objFound).build(); } } 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 5456cd9179c..7994e3d192f 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 @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.referralmanagement.hfreferral.HFReferral; import org.springframework.beans.factory.annotation.Autowired; 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 181aa1b6a55..83971874a2f 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 @@ -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.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.referralmanagement.Referral; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; 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 3832d8bd7e3..4b4d961b1f2 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 @@ -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.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.springframework.beans.factory.annotation.Autowired; 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 c3c287bcff3..bc6aa52dc33 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 @@ -9,6 +9,7 @@ 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.hfreferral.HFReferral; import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; import org.egov.common.models.referralmanagement.hfreferral.HFReferralRequest; @@ -169,12 +170,12 @@ public List update(HFReferralBulkRequest hfReferralRequest, boolean } // Method to search for HFReferrals based on certain criteria - public List search(HFReferralSearchRequest referralSearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) { + public SearchResponse 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()); @@ -186,11 +187,12 @@ public List search(HFReferralSearchRequest referralSearchRequest, referralSearchRequest.getHfReferral()); log.info("Fetching referrals with IDs: {}", ids); - return hfReferralRepository.findById(ids, includeDeleted, idFieldName).stream() + List hfReferrals = hfReferralRepository.findById(ids, idFieldName, includeDeleted).getResponse().stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); + return SearchResponse.builder().response(hfReferrals).build(); } log.info("Searching referrals using criteria"); 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 index 3c09df3edde..7afa7bc0922 100644 --- 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 @@ -1,15 +1,18 @@ 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 com.jayway.jsonpath.JsonPath; 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; @@ -22,6 +25,11 @@ 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.mdms.model.MasterDetail; +import org.egov.mdms.model.MdmsCriteria; +import org.egov.mdms.model.MdmsCriteriaReq; +import org.egov.mdms.model.ModuleDetail; + import org.egov.referralmanagement.config.ReferralManagementConfiguration; 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/util/ValidatorUtil.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/util/ValidatorUtil.java index 043c7d6a1b5..3541cb2d4dc 100644 --- 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 @@ -1,7 +1,7 @@ package org.egov.referralmanagement.util; -import digit.models.coremodels.UserSearchRequest; import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.user.UserSearchRequest; import org.egov.common.service.UserService; import org.springframework.util.CollectionUtils; 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 index 3011cef48ce..d7e81c7e9a4 100644 --- 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 @@ -82,7 +82,8 @@ public Map> validate(HFReferralBulkRequest request) { try { // Query the repository to find existing entities existingReferrals = hfReferralRepository.find(hfReferralSearch, hfReferrals.size(), 0, - hfReferrals.get(0).getTenantId(), null, false); + hfReferrals.get(0).getTenantId(), null, false).getResponse() + ; } catch (Exception e) { // Handle query builder exception log.error("Search failed for HFReferral with error: {}", e.getMessage(), e); 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 index e5d62bfee0a..83011aceec9 100644 --- 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 @@ -61,7 +61,7 @@ public Map> validate(HFReferralBulkRequest request) { if (!iMap.isEmpty()) { List hfReferralIds = new ArrayList<>(iMap.keySet()); List existingHfReferrals = hfReferralRepository.findById(hfReferralIds, - false, getIdFieldName(idMethod)); + getIdFieldName(idMethod), false).getResponse(); List entitiesWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(iMap, existingHfReferrals, idMethod); entitiesWithMismatchedRowVersion.forEach(hfReferral -> { 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 f09a4c578e8..c09a02bebfa 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 @@ -6,6 +6,7 @@ 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.hfreferral.HFReferral; import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; @@ -107,7 +108,7 @@ public ResponseEntity referralV1SearchPost( @ApiParam(value = "HFReferral Search.", required = true) @Valid @RequestBody HFReferralSearchRequest request ) throws Exception { - List hfReferrals = hfReferralService.search( + SearchResponse searchResponse = hfReferralService.search( request, urlParams.getLimit(), urlParams.getOffset(), @@ -115,7 +116,10 @@ public ResponseEntity referralV1SearchPost( urlParams.getLastChangedSince(), urlParams.getIncludeDeleted()); HFReferralBulkResponse response = HFReferralBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).hfReferrals(hfReferrals).build(); + .createResponseInfo(request.getRequestInfo(), true)) + .hfReferrals(searchResponse.getResponse()) + .totalCount(searchResponse.getTotalCount()) + .build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/resource-estimation-service/CHANGELOG.md b/health-services/resource-estimation-service/CHANGELOG.md deleted file mode 100644 index e5ce4491284..00000000000 --- a/health-services/resource-estimation-service/CHANGELOG.md +++ /dev/null @@ -1,8 +0,0 @@ -# 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/src/main/java/org/egov/processor/config/ServiceConstants.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java deleted file mode 100644 index 797c9a894c3..00000000000 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java +++ /dev/null @@ -1,72 +0,0 @@ -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 = "^(?!\\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)$"; - - 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; - - 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/web/models/MetricDetail.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/MetricDetail.java deleted file mode 100644 index 32a5c0b4ccc..00000000000 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/MetricDetail.java +++ /dev/null @@ -1,34 +0,0 @@ -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-generator/CHANGELOG.md b/health-services/resource-generator/CHANGELOG.md new file mode 100644 index 00000000000..f56811de913 --- /dev/null +++ b/health-services/resource-generator/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog + +## 1.0.0 - 2024-12-03 +#### Resource Generator Service +The Resource Generator Service introduces comprehensive functionalities for microplanning resource estimation and campaign integration: + +1. File Processing: Supports Excel, Shapefiles, and GeoJSON for resource estimation and validates input data against the plan configuration. +2. Resource Estimation: Calculates resources using predefined formulas and updates plans by publishing data to relevant topics. +3. Boundary Validation: Ensures boundary integrity and validates data during resource calculations. +4. Process Triggers: Automates Plan-Facility creation, Census data creation, and Plan generation based on file uploads and validations. +5. Campaign Integration: Integrates estimated resources and boundaries with the Campaign Manager for streamlined planning. +6. Result Upload: Automates the upload of approved resource sheets to the filestore and updates plan configurations. +7. HCM Integration: Updates project factory with resource estimates for accurate campaign planning. \ No newline at end of file diff --git a/health-services/resource-estimation-service/LOCALSETUP.md b/health-services/resource-generator/LOCALSETUP.md similarity index 100% rename from health-services/resource-estimation-service/LOCALSETUP.md rename to health-services/resource-generator/LOCALSETUP.md diff --git a/health-services/resource-estimation-service/README.md b/health-services/resource-generator/README.md similarity index 100% rename from health-services/resource-estimation-service/README.md rename to health-services/resource-generator/README.md diff --git a/health-services/resource-estimation-service/pom.xml b/health-services/resource-generator/pom.xml similarity index 95% rename from health-services/resource-estimation-service/pom.xml rename to health-services/resource-generator/pom.xml index c73dd06629d..33ac3c4c7d6 100644 --- a/health-services/resource-estimation-service/pom.xml +++ b/health-services/resource-generator/pom.xml @@ -1,7 +1,7 @@ 4.0.0 org.egov - resource-estimation-service + resource-generator jar file-processor-utility 1.0.0 @@ -98,6 +98,12 @@ tracer 2.9.0-SNAPSHOT + + org.egov.services + services-common + 2.9.0-SNAPSHOT + compile + org.egov mdms-client diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/Main.java b/health-services/resource-generator/src/main/java/org/egov/processor/Main.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/Main.java rename to health-services/resource-generator/src/main/java/org/egov/processor/Main.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/Configuration.java b/health-services/resource-generator/src/main/java/org/egov/processor/config/Configuration.java similarity index 54% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/config/Configuration.java rename to health-services/resource-generator/src/main/java/org/egov/processor/config/Configuration.java index 12ce0667abd..c652337ba28 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/Configuration.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/config/Configuration.java @@ -11,6 +11,8 @@ import lombok.NoArgsConstructor; import lombok.Setter; +import java.util.List; + @Component @Data @Import({ TracerConfiguration.class }) @@ -27,12 +29,18 @@ public class Configuration { @Value("${egov.mdms.search.endpoint}") private String mdmsEndPoint; + @Value("${egov.mdms.search.v2.endpoint}") + private String mdmsV2EndPoint; + @Value("${egov.plan.config.host}") private String planConfigHost; @Value("${egov.plan.config.endpoint}") private String planConfigEndPoint; + @Value("${egov.plan.search.endpoint}") + private String planSearchEndPoint; + // Filestore @Value("${egov.filestore.service.host}") @@ -53,18 +61,18 @@ public class Configuration { @Value("${egov.project.factory.update.endpoint}") private String campaignIntegrationUpdateEndPoint; + @Value("${egov.project.factory.data.create.endpoint}") + private String campaignIntegrationDataCreateEndPoint; + + @Value("${egov.project.factory.fetch.from.microplan.endpoint}") + private String campaignIntegrationFetchFromMicroplanEndPoint; + @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; @@ -77,4 +85,51 @@ public class Configuration { @Value("${egov.locale.search.endpoint}") private String egovLocaleSearchEndpoint; + //trigger statuses + @Value("${plan.config.trigger.plan.estimates.status}") + private String planConfigTriggerPlanEstimatesStatus; + + @Value("${plan.config.trigger.census.records.status}") + private String planConfigTriggerCensusRecordsStatus; + + @Value("${plan.config.update.plan.estimates.into.output.file.status}") + private String planConfigUpdatePlanEstimatesIntoOutputFileStatus; + + @Value("${plan.config.trigger.plan.facility.mappings.status}") + private String planConfigTriggerPlanFacilityMappingsStatus; + + //Kafka topics for creating or updating records in dependent microservices + @Value("${resource.microplan.create.topic}") + private String resourceMicroplanCreateTopic; + + @Value("${resource.update.plan.config.consumer.topic}") + private String resourceUpdatePlanConfigConsumerTopic; + + @Value("${resource.census.create.topic}") + private String resourceCensusCreateTopic; + + //Default + @Value("${resource.default.offset}") + private Integer defaultOffset; + + @Value("${resource.default.limit}") + private Integer defaultLimit; + + //census additonal field configs + @Value("${census.additional.field.override.keys}") + public List censusAdditionalFieldOverrideKeys; + + @Value("${census.additional.field.prefix.append.keys}") + public List censusAdditionalPrefixAppendKeys; + + @Value("${census.additional.field.show.on.ui.false.keys}") + public List censusAdditionalFieldShowOnUIFalseKeys; + + //census host + @Value("${egov.census.host}") + private String censusHost; + + @Value("${egov.census.search.endpoint}") + private String censusSearchEndPoint; + } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/MainConfiguration.java b/health-services/resource-generator/src/main/java/org/egov/processor/config/MainConfiguration.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/config/MainConfiguration.java rename to health-services/resource-generator/src/main/java/org/egov/processor/config/MainConfiguration.java diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java b/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java new file mode 100644 index 00000000000..7200f29cecc --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/config/ServiceConstants.java @@ -0,0 +1,123 @@ +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 ERROR_WHILE_FETCHING_FROM_CENSUS = "Exception occurred while fetching records from census: "; + + 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 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 FILE_NOT_FOUND_CODE = "FILE_NOT_FOUND"; + public static final String FILE_NOT_FOUND_MESSAGE = "No file with the specified templateIdentifier found - "; + + public static final String UNABLE_TO_CREATE_ADDITIONAL_DETAILS_CODE = "UNABLE_TO_CREATE_ADDITIONAL_DETAILS"; + public static final String UNABLE_TO_CREATE_ADDITIONAL_DETAILS_MESSAGE = "Unable to create additional details for facility creation."; + + public static final String NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_CODE = "NO_PLAN_FOUND_FOR_GIVEN_DETAILS"; + public static final String NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_MESSAGE = "Census records do not exists for the given details: "; + + public static final String NO_PLAN_FOUND_FOR_GIVEN_DETAILS_CODE = "NO_PLAN_FOUND_FOR_GIVEN_DETAILS"; + public static final String NO_PLAN_FOUND_FOR_GIVEN_DETAILS_MESSAGE = "Plan records do not exists for the given details: "; + + public static final String BOUNDARY_CODE = "HCM_ADMIN_CONSOLE_BOUNDARY_CODE"; + public static final String TOTAL_POPULATION = "HCM_ADMIN_CONSOLE_TOTAL_POPULATION"; + + 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_PUSHING_TO_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 ERROR_WHILE_DATA_CREATE_CALL = "Exception occurred while creating data for campaign - "; + public static final String ERROR_WHILE_CALLING_MICROPLAN_API = + "Unexpected error while calling fetch from Microplan API for plan config Id: "; + + public static final String FILE_NAME = "output.xls"; + public static final String FILE_TYPE = "boundaryWithTarget"; + public static final String FILE_TEMPLATE_IDENTIFIER_POPULATION = "Population"; + public static final String FILE_TEMPLATE_IDENTIFIER_FACILITY = "Facilities"; + 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 MDMS_SCHEMA_ADMIN_SCHEMA = "adminSchema"; + public static final String MDMS_ADMIN_CONSOLE_MODULE_NAME = "HCM-ADMIN-CONSOLE"; + public static final String BOUNDARY = "boundary"; + public static final String DOT_SEPARATOR = "."; + public static final String MICROPLAN_PREFIX = "MP-"; + + //MDMS field Constants + public static final String DATA = "data"; + public static final String PROPERTIES = "properties"; + public static final String NUMBER_PROPERTIES = "numberProperties"; + public static final String STRING_PROPERTIES = "stringProperties"; + public static final String NAME = "name"; + + public static final String ERROR_WHILE_UPDATING_PLAN_CONFIG = "Exception occurred while updating plan configuration."; + public static final String ERROR_WHILE_SEARCHING_PLAN = "Exception occurred while search plans."; + + 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)$"; + + 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; + + public static final String MDMS_LOCALE_SEARCH_MODULE ="rainmaker-microplanning,rainmaker-boundary-undefined,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"; + + //override sheet names + public static final String HCM_ADMIN_CONSOLE_BOUNDARY_DATA = "HCM_ADMIN_CONSOLE_BOUNDARY_DATA"; + public static final String READ_ME_SHEET_NAME = "readMeSheetName"; + + //Workflow constants + public static final String WORKFLOW_ACTION_INITIATE = "INITIATE"; + public static final String WORKFLOW_COMMENTS_INITIATING_CENSUS = "Initiating census record creation"; + public static final String WORKFLOW_COMMENTS_INITIATING_ESTIMATES = "Initiating plan estimation record creation"; + + //Facility Create constants + public static final String TYPE_FACILITY = "facility"; + public static final String ACTION_CREATE = "create"; + public static final String SOURCE_KEY = "source"; + public static final String MICROPLAN_SOURCE_KEY = "microplan"; + public static final String MICROPLAN_ID_KEY = "microplanId"; + + //Census additional field constants + public static final String UPLOADED_KEY = "UPLOADED_"; + public static final String CONFIRMED_KEY = "CONFIRMED_"; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/PlanConsumer.java b/health-services/resource-generator/src/main/java/org/egov/processor/kafka/PlanConsumer.java similarity index 66% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/PlanConsumer.java rename to health-services/resource-generator/src/main/java/org/egov/processor/kafka/PlanConsumer.java index 2aa31907413..8b0c54a4010 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/PlanConsumer.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/kafka/PlanConsumer.java @@ -1,11 +1,9 @@ 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.config.Configuration; 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; @@ -13,6 +11,9 @@ import org.springframework.kafka.support.KafkaHeaders; import org.springframework.messaging.handler.annotation.Header; import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.util.Map; @Component @Slf4j @@ -22,16 +23,22 @@ public class PlanConsumer { private ResourceEstimationService resourceEstimationService; - public PlanConsumer(ObjectMapper objectMapper, ResourceEstimationService resourceEstimationService) { + private Configuration config; + + public PlanConsumer(ObjectMapper objectMapper, ResourceEstimationService resourceEstimationService, Configuration config) { this.objectMapper = objectMapper; this.resourceEstimationService = resourceEstimationService; + this.config = config; } @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)) { + if (!ObjectUtils.isEmpty(planConfigurationRequest.getPlanConfiguration().getWorkflow()) && (planConfigurationRequest.getPlanConfiguration().getStatus().equals(config.getPlanConfigTriggerPlanEstimatesStatus()) + || planConfigurationRequest.getPlanConfiguration().getStatus().equals(config.getPlanConfigTriggerCensusRecordsStatus()) + || planConfigurationRequest.getPlanConfiguration().getStatus().equals(config.getPlanConfigTriggerPlanFacilityMappingsStatus()) + || planConfigurationRequest.getPlanConfiguration().getStatus().equals(config.getPlanConfigUpdatePlanEstimatesIntoOutputFileStatus()))) { resourceEstimationService.estimateResources(planConfigurationRequest); log.info("Successfully estimated resources for plan."); } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/Producer.java b/health-services/resource-generator/src/main/java/org/egov/processor/kafka/Producer.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/Producer.java rename to health-services/resource-generator/src/main/java/org/egov/processor/kafka/Producer.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/repository/ServiceRequestRepository.java b/health-services/resource-generator/src/main/java/org/egov/processor/repository/ServiceRequestRepository.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/repository/ServiceRequestRepository.java rename to health-services/resource-generator/src/main/java/org/egov/processor/repository/ServiceRequestRepository.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java b/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java similarity index 74% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java rename to health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java index ee005cd81c8..6f2326d628a 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/service/ExcelParser.java @@ -1,36 +1,19 @@ 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 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; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; 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; -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.LocaleUtil; -import org.egov.processor.util.MdmsUtil; -import org.egov.processor.util.ParsingUtil; -import org.egov.processor.util.PlanUtil; +import org.egov.processor.util.*; +import org.egov.processor.web.models.*; 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; -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; @@ -40,13 +23,16 @@ 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 java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; -import lombok.extern.slf4j.Slf4j; +import static org.egov.processor.config.ServiceConstants.HCM_ADMIN_CONSOLE_BOUNDARY_DATA; +import static org.egov.processor.config.ServiceConstants.READ_ME_SHEET_NAME; @Slf4j @Service @@ -72,9 +58,15 @@ public class ExcelParser implements FileParser { private LocaleUtil localeUtil; + private CensusUtil censusUtil; + + private EnrichmentUtil enrichmentUtil; + + private PlanConfigurationUtil planConfigurationUtil; + public ExcelParser(ObjectMapper objectMapper, ParsingUtil parsingUtil, FilestoreUtil filestoreUtil, - CalculationUtil calculationUtil, PlanUtil planUtil, CampaignIntegrationUtil campaignIntegrationUtil, - Configuration config, MdmsUtil mdmsUtil, BoundaryUtil boundaryUtil,LocaleUtil localeUtil) { + CalculationUtil calculationUtil, PlanUtil planUtil, CampaignIntegrationUtil campaignIntegrationUtil, + Configuration config, MdmsUtil mdmsUtil, BoundaryUtil boundaryUtil, LocaleUtil localeUtil, CensusUtil censusUtil, EnrichmentUtil enrichmentUtil, PlanConfigurationUtil planConfigurationUtil) { this.objectMapper = objectMapper; this.parsingUtil = parsingUtil; this.filestoreUtil = filestoreUtil; @@ -85,7 +77,10 @@ public ExcelParser(ObjectMapper objectMapper, ParsingUtil parsingUtil, Filestore this.mdmsUtil = mdmsUtil; this.boundaryUtil = boundaryUtil; this.localeUtil = localeUtil; - } + this.censusUtil = censusUtil; + this.enrichmentUtil = enrichmentUtil; + this.planConfigurationUtil = planConfigurationUtil; + } /** * Parses file data, extracts information from the file, and processes it. @@ -99,7 +94,7 @@ public ExcelParser(ObjectMapper objectMapper, ParsingUtil parsingUtil, Filestore */ @Override public Object parseFileData(PlanConfigurationRequest planConfigurationRequest, String fileStoreId, - Object campaignResponse) { + Object campaignResponse) { PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); byte[] byteArray = filestoreUtil.getFile(planConfig.getTenantId(), fileStoreId); File file = parsingUtil.convertByteArrayToFile(byteArray, ServiceConstants.FILE_EXTENSION); @@ -108,7 +103,8 @@ public Object parseFileData(PlanConfigurationRequest planConfigurationRequest, S throw new CustomException("FileNotFound", "The file with ID " + fileStoreId + " was not found in the tenant " + planConfig.getTenantId()); } - return processExcelFile(planConfigurationRequest, file, fileStoreId, campaignResponse); + processExcelFile(planConfigurationRequest, file, fileStoreId, campaignResponse); + return null; } /** @@ -122,20 +118,17 @@ public Object parseFileData(PlanConfigurationRequest planConfigurationRequest, S * @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, + private void 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; + processSheets(planConfigurationRequest, fileStoreId, campaignResponse, workbook, + campaignBoundaryList, dataFormatter); + uploadFileAndIntegrateCampaign(planConfigurationRequest, campaignResponse, + workbook, campaignBoundaryList, campaignResourcesList); } catch (FileNotFoundException e) { log.error("File not found: {}", e.getMessage()); throw new CustomException("FileNotFound", "The specified file was not found."); @@ -154,28 +147,26 @@ private String processExcelFile(PlanConfigurationRequest planConfigurationReques * * @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, + private void uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfigurationRequest, + Object campaignResponse, Workbook workbook, List campaignBoundaryList, List campaignResourcesList) { File fileToUpload = null; try { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); fileToUpload = convertWorkbookToXls(workbook); - String uploadedFileStoreId = uploadConvertedFile(fileToUpload, planConfig.getTenantId()); - - if (config.isIntegrateWithAdminConsole()) { - campaignIntegrationUtil.updateCampaignResources(uploadedFileStoreId, campaignResourcesList, - fileToUpload.getName()); - - campaignIntegrationUtil.updateCampaignDetails(planConfigurationRequest, campaignResponse, - campaignBoundaryList, campaignResourcesList); + if (planConfig.getStatus().equals(config.getPlanConfigTriggerPlanEstimatesStatus())) { + String uploadedFileStoreId = uploadConvertedFile(fileToUpload, planConfig.getTenantId()); + planUtil.setFileStoreIdForPopulationTemplate(planConfigurationRequest, uploadedFileStoreId); + planUtil.update(planConfigurationRequest); } - return uploadedFileStoreId; + if (planConfig.getStatus().equals(config.getPlanConfigUpdatePlanEstimatesIntoOutputFileStatus()) && config.isIntegrateWithAdminConsole()) { + String uploadedFileStoreId = uploadConvertedFile(fileToUpload, planConfig.getTenantId()); + campaignIntegrationUtil.updateResourcesInProjectFactory(planConfigurationRequest, uploadedFileStoreId); + } } finally { try { if (fileToUpload != null && !fileToUpload.delete()) { @@ -191,32 +182,48 @@ private String uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfi * 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 request 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 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. */ - private void processSheets(PlanConfigurationRequest planConfigurationRequest, String fileStoreId, - 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); + private void processSheets(PlanConfigurationRequest request, String fileStoreId, + Object campaignResponse, Workbook excelWorkbook, + List campaignBoundaryList, + DataFormatter dataFormatter) { + CampaignResponse campaign = campaignIntegrationUtil.parseCampaignResponse(campaignResponse); + LocaleResponse localeResponse = localeUtil.searchLocale(request); + Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), + request.getPlanConfiguration().getTenantId()); + planConfigurationUtil.orderPlanConfigurationOperations(request); + enrichmentUtil.enrichResourceMapping(request, localeResponse, campaign.getCampaign().get(0).getProjectType(), fileStoreId); + Map attributeNameVsDataTypeMap = prepareAttributeVsIndexMap(request, + fileStoreId, campaign, request.getPlanConfiguration(), mdmsData); + + List boundaryCodeList = getBoundaryCodeList(request, campaign); + Map mappedValues = request.getPlanConfiguration().getResourceMapping().stream() + .filter(f -> f.getFilestoreId().equals(fileStoreId)) + .collect(Collectors.toMap( + ResourceMapping::getMappedTo, + ResourceMapping::getMappedFrom, + (existing, replacement) -> existing, + LinkedHashMap::new + )); excelWorkbook.forEach(excelWorkbookSheet -> { - 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, - campaignBoundaryList, attributeNameVsDataTypeMap, boundaryCodeList); + if (isSheetAllowedToProcess(request, excelWorkbookSheet.getSheetName(), localeResponse)) { + if (request.getPlanConfiguration().getStatus().equals(config.getPlanConfigTriggerPlanEstimatesStatus())) { + enrichmentUtil.enrichsheetWithApprovedCensusRecords(excelWorkbookSheet, request, fileStoreId, mappedValues); + processRows(request, excelWorkbookSheet, dataFormatter, fileStoreId, + campaignBoundaryList, attributeNameVsDataTypeMap, boundaryCodeList); + } else if (request.getPlanConfiguration().getStatus().equals(config.getPlanConfigTriggerCensusRecordsStatus())) { + processRowsForCensusRecords(request, excelWorkbookSheet, + fileStoreId, attributeNameVsDataTypeMap, boundaryCodeList, campaign.getCampaign().get(0).getHierarchyType()); + } else if (request.getPlanConfiguration().getStatus().equals(config.getPlanConfigUpdatePlanEstimatesIntoOutputFileStatus())) { + enrichmentUtil.enrichsheetWithApprovedPlanEstimates(excelWorkbookSheet, request, fileStoreId, mappedValues); + } } }); } @@ -241,8 +248,41 @@ private void processSheets(PlanConfigurationRequest planConfigurationRequest, St */ private void processRows(PlanConfigurationRequest planConfigurationRequest, Sheet sheet, DataFormatter dataFormatter, String fileStoreId, List campaignBoundaryList, Map attributeNameVsDataTypeMap, List boundaryCodeList) { PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + performRowLevelCalculations(planConfigurationRequest, sheet, dataFormatter, fileStoreId, campaignBoundaryList, planConfig, attributeNameVsDataTypeMap, boundaryCodeList); + } + + private void processRowsForCensusRecords(PlanConfigurationRequest planConfigurationRequest, Sheet sheet, String fileStoreId, Map attributeNameVsDataTypeMap, List boundaryCodeList, String hierarchyType) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + + Map mappedValues = planConfig.getResourceMapping().stream() + .filter(f -> f.getFilestoreId().equals(fileStoreId)) + .collect(Collectors.toMap( + ResourceMapping::getMappedTo, + ResourceMapping::getMappedFrom, + (existing, replacement) -> existing, + LinkedHashMap::new + )); + + Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); + Integer indexOfBoundaryCode = parsingUtil.getIndexOfBoundaryCode(0, + parsingUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); Row firstRow = null; - performRowLevelCalculations(planConfigurationRequest, sheet, dataFormatter, fileStoreId, campaignBoundaryList, planConfig, attributeNameVsDataTypeMap, boundaryCodeList, firstRow); + + for (Row row : sheet) { + if (parsingUtil.isRowEmpty(row)) + continue; + + if (row.getRowNum() == 0) { + firstRow = row; + continue; + } + + validateRows(indexOfBoundaryCode, row, firstRow, attributeNameVsDataTypeMap, mappedValues, mapOfColumnNameAndIndex, + planConfigurationRequest, boundaryCodeList, sheet); + JsonNode currentRow = createFeatureNodeFromRow(row, mapOfColumnNameAndIndex); + + censusUtil.create(planConfigurationRequest, currentRow, mappedValues, hierarchyType); + } } /** @@ -250,12 +290,11 @@ private void processRows(PlanConfigurationRequest planConfigurationRequest, Shee * * @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(), + CampaignResponse campaign) { + BoundarySearchResponse boundarySearchResponse = boundaryUtil.search(planConfigurationRequest.getPlanConfiguration().getTenantId(), campaign.getCampaign().get(0).getHierarchyType(), planConfigurationRequest); List boundaryList = new ArrayList<>(); List boundaryCodeList = getAllBoundaryPresentforHierarchyType( @@ -272,29 +311,17 @@ private List getBoundaryCodeList(PlanConfigurationRequest planConfigurat * @param planConfig The configuration details specific to the plan. * @return A map of attribute names to their corresponding indices or data types. */ + + + //TODO: fetch from adminSchema master private Map prepareAttributeVsIndexMap(PlanConfigurationRequest planConfigurationRequest, - String fileStoreId, CampaignResponse campaign, PlanConfiguration planConfig) { - Object mdmsData = mdmsUtil.fetchMdmsData(planConfigurationRequest.getRequestInfo(), - planConfigurationRequest.getPlanConfiguration().getTenantId()); + String fileStoreId, CampaignResponse campaign, PlanConfiguration planConfig, Object mdmsData) { 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; + return mdmsUtil.filterMasterData(mdmsData.toString(), file.getInputFileType(), + file.getTemplateIdentifier(), campaign.getCampaign().get(0).getProjectType()); } - - /** - * 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. @@ -309,14 +336,23 @@ private CampaignResponse parseCampaignResponse(Object campaignResponse) { * @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) { + PlanConfiguration planConfig, Map attributeNameVsDataTypeMap, List boundaryCodeList) { + Row firstRow = null; + 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 = parsingUtil.getIndexOfBoundaryCode(0, + parsingUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); + for (Row row : sheet) { - if(isRowEmpty(row)) + if(parsingUtil.isRowEmpty(row)) continue; if (row.getRowNum() == 0) { @@ -325,49 +361,20 @@ private void performRowLevelCalculations(PlanConfigurationRequest planConfigurat } 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, sheet); - JsonNode feature = createFeatureNodeFromRow(row, dataFormatter, mapOfColumnNameAndIndex); + JsonNode feature = createFeatureNodeFromRow(row, 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); - } - } - /** - * 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. @@ -407,7 +414,7 @@ private void performCalculationsOnOperations(Sheet sheet, PlanConfiguration plan * * @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. + * @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) { @@ -458,12 +465,10 @@ private File convertWorkbookToXls(Workbook workbook) { * 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) { + private JsonNode createFeatureNodeFromRow(Row row, Map columnIndexMap) { ObjectNode featureNode = objectMapper.createObjectNode(); ObjectNode propertiesNode = featureNode.putObject("properties"); @@ -474,47 +479,51 @@ private JsonNode createFeatureNodeFromRow(Row row, DataFormatter dataFormatter, // 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; - } + if (cell == null) { + // Handle null cells if needed + propertiesNode.putNull(columnName); + continue; + } - 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; + case STRING: + propertiesNode.put(columnName, cell.getStringCellValue()); + break; + case NUMERIC: + if (DateUtil.isCellDateFormatted(cell)) { + // Handle date values + propertiesNode.put(columnName, cell.getDateCellValue().toString()); + } else { + propertiesNode.put(columnName, BigDecimal.valueOf(cell.getNumericCellValue())); + } + break; + case BOOLEAN: + propertiesNode.put(columnName, cell.getBooleanCellValue()); + break; + case FORMULA: + // Attempt to get the cached formula result value directly + switch (cell.getCachedFormulaResultType()) { + case NUMERIC: + propertiesNode.put(columnName, BigDecimal.valueOf(cell.getNumericCellValue())); + break; + case STRING: + propertiesNode.put(columnName, cell.getStringCellValue()); + break; + case BOOLEAN: + propertiesNode.put(columnName, cell.getBooleanCellValue()); + break; + default: + propertiesNode.putNull(columnName); + break; + } + break; + default: + propertiesNode.putNull(columnName); + break; } } - System.out.println(); // Move to the next line after printing the row + + return featureNode; } /** @@ -543,13 +552,13 @@ public void validateRows(Integer indexOfBoundaryCode, Row row, Row columnHeaderR boundaryCodeList); } catch (JsonProcessingException e) { log.info(ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1) + " at sheet - " + sheet); - planConfigurationRequest.getPlanConfiguration().setStatus(StatusEnum.INVALID_DATA); + planConfigurationRequest.getPlanConfiguration().setStatus("INVALID_DATA"); planUtil.update(planConfigurationRequest); throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), ServiceConstants.INPUT_IS_NOT_VALID + row.getRowNum() + " at sheet - " + sheet); } catch (CustomException customException) { log.info(customException.toString()+ "at sheet - " + sheet.getSheetName()); - planConfigurationRequest.getPlanConfiguration().setStatus(StatusEnum.INVALID_DATA); + planConfigurationRequest.getPlanConfiguration().setStatus("INVALID_DATA"); planUtil.update(planConfigurationRequest); throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), customException.getMessage()+ "at sheet - " + sheet.getSheetName()); @@ -718,13 +727,14 @@ 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,LocaleResponse localeResponse) { + private boolean isSheetAllowedToProcess(PlanConfigurationRequest planConfigurationRequest, String sheetName, LocaleResponse localeResponse) { Map mdmsDataConstants = mdmsUtil.fetchMdmsDataForCommonConstants( planConfigurationRequest.getRequestInfo(), planConfigurationRequest.getPlanConfiguration().getTenantId()); - String value = (String) mdmsDataConstants.get("readMeSheetName"); + for (Locale locale : localeResponse.getMessages()) { - if ((locale.getCode().equalsIgnoreCase(value))) { + if ((locale.getCode().equalsIgnoreCase((String) mdmsDataConstants.get(READ_ME_SHEET_NAME))) + || locale.getCode().equalsIgnoreCase(HCM_ADMIN_CONSOLE_BOUNDARY_DATA)) { if (sheetName.equals(locale.getMessage())) return false; } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/FileParser.java b/health-services/resource-generator/src/main/java/org/egov/processor/service/FileParser.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/service/FileParser.java rename to health-services/resource-generator/src/main/java/org/egov/processor/service/FileParser.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/GeoJsonParser.java b/health-services/resource-generator/src/main/java/org/egov/processor/service/GeoJsonParser.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/service/GeoJsonParser.java rename to health-services/resource-generator/src/main/java/org/egov/processor/service/GeoJsonParser.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ResourceEstimationService.java b/health-services/resource-generator/src/main/java/org/egov/processor/service/ResourceEstimationService.java similarity index 82% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ResourceEstimationService.java rename to health-services/resource-generator/src/main/java/org/egov/processor/service/ResourceEstimationService.java index c1b1ab07b7a..978633933b9 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ResourceEstimationService.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/service/ResourceEstimationService.java @@ -1,9 +1,7 @@ package org.egov.processor.service; -import java.util.HashMap; -import java.util.Map; - +import lombok.extern.slf4j.Slf4j; import org.egov.processor.config.Configuration; import org.egov.processor.config.ServiceConstants; import org.egov.processor.repository.ServiceRequestRepository; @@ -11,10 +9,12 @@ 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.CampaignResponse; import org.egov.processor.web.models.campaignManager.CampaignSearchRequest; import org.springframework.stereotype.Service; -import lombok.extern.slf4j.Slf4j; +import java.util.HashMap; +import java.util.Map; @Service @Slf4j @@ -48,7 +48,8 @@ public void estimateResources(PlanConfigurationRequest planConfigurationRequest) Map parserMap = getInputFileTypeMap(); Object campaignSearchResponse = performCampaignSearch(planConfigurationRequest); - processFiles(planConfigurationRequest, planConfiguration, parserMap, campaignSearchResponse); + processFacilityFile(planConfigurationRequest, campaignSearchResponse); + processFiles(planConfigurationRequest, planConfiguration, parserMap, campaignSearchResponse); } /** @@ -108,5 +109,21 @@ public Map getInputFileTypeMap() return parserMap; } + + /** + * Processes the facility file by parsing the campaign response and initiating + * a data creation call to the Project Factory service. + * + * @param planConfigurationRequest the request containing plan configuration details + * @param campaignResponseObject the campaign response object to be parsed + */ + public void processFacilityFile(PlanConfigurationRequest planConfigurationRequest, Object campaignResponseObject) { + if (planConfigurationRequest.getPlanConfiguration().getStatus().equals(config.getPlanConfigTriggerPlanFacilityMappingsStatus())) { + CampaignResponse campaignResponse = campaignIntegrationUtil.parseCampaignResponse(campaignResponseObject); + campaignIntegrationUtil.createProjectFactoryDataCall(planConfigurationRequest, campaignResponse); + log.info("Facility Data creation successful."); + } + } + } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ShapeFileParser.java b/health-services/resource-generator/src/main/java/org/egov/processor/service/ShapeFileParser.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ShapeFileParser.java rename to health-services/resource-generator/src/main/java/org/egov/processor/service/ShapeFileParser.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/BoundaryUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/BoundaryUtil.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/util/BoundaryUtil.java rename to health-services/resource-generator/src/main/java/org/egov/processor/util/BoundaryUtil.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CalculationUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/CalculationUtil.java similarity index 74% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CalculationUtil.java rename to health-services/resource-generator/src/main/java/org/egov/processor/util/CalculationUtil.java index d6b53891a8b..551206d9b94 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CalculationUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/CalculationUtil.java @@ -2,13 +2,6 @@ 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; @@ -16,6 +9,13 @@ import org.egov.processor.web.models.PlanConfigurationRequest; import org.egov.tracer.model.CustomException; import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import static org.egov.processor.config.ServiceConstants.PROPERTIES; @@ -86,21 +86,23 @@ public void calculateResources(JsonNode jsonNode, PlanConfigurationRequest planC /** * 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. + * @param resultMap The map containing previous results. + * @param feature The JSON node feature. + * @param assumptionValueMap The assumptions and their value map from plan config. + * @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) { + private BigDecimal getInputValueFromFeatureOrMap(JsonNode feature, Map resultMap, Map assumptionValueMap, String input, String columnName) { + // Try to fetch the value from resultMap, If not found in the resultMap, use the assumptionValueMap as a fallback + BigDecimal inputValue = resultMap.getOrDefault(input, assumptionValueMap.get(input)); + + // Try to fetch the value from the feature (if it exists) + if(ObjectUtils.isEmpty(inputValue)) { + if (feature.has(PROPERTIES) && feature.get(PROPERTIES).has(columnName)) { 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 { @@ -109,12 +111,12 @@ public BigDecimal getInputValueFromJsonFeature(Map resultMap } return value; } catch (NumberFormatException | NullPointerException e) { - return BigDecimal.ZERO; - } - } else { - throw new CustomException("INPUT_VALUE_NOT_FOUND", "Input value not found: " + input); + // Handle potential parsing issues + throw new CustomException("INPUT_VALUE_NOT_FOUND", "Input value not found: " + input); } } } + + return inputValue; } /** @@ -127,12 +129,18 @@ public BigDecimal getInputValueFromJsonFeature(Map resultMap * @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) - { + public BigDecimal calculateResult(Operation operation, JsonNode feature, Map mappedValues, Map assumptionValueMap, Map resultMap) { + // Fetch the input value String input = operation.getInput(); String inputFromMapping = mappedValues.get(input); - BigDecimal inputValue = getInputValueFromJsonFeature(resultMap, feature, operation.getInput(), inputFromMapping); - BigDecimal assumptionValue = assumptionValueMap.get(operation.getAssumptionValue()); + BigDecimal inputValue = getInputValueFromFeatureOrMap(feature, resultMap, assumptionValueMap, input, inputFromMapping); + + // Fetch the assumption value with priority: feature -> resultMap -> assumptionValueMap + String assumptionKey = operation.getAssumptionValue(); + String assumptionFromMapping = mappedValues.get(assumptionKey); + BigDecimal assumptionValue = getInputValueFromFeatureOrMap(feature, resultMap, assumptionValueMap, assumptionKey, assumptionFromMapping); + + // Calculate and return the output 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-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java similarity index 61% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java rename to health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java index d14b3512aef..9bfbe7cb62c 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java @@ -1,48 +1,25 @@ 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 com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; 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.processor.web.models.campaignManager.*; import org.egov.tracer.model.CustomException; import org.springframework.stereotype.Component; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.*; +import java.util.Map.Entry; -import lombok.extern.slf4j.Slf4j; +import static org.egov.processor.config.ServiceConstants.*; @Component @Slf4j @@ -51,6 +28,7 @@ public class CampaignIntegrationUtil { private ServiceRequestRepository serviceRequestRepository; private Configuration config; private ObjectMapper mapper; + private ParsingUtil parsingUtil; public CampaignIntegrationUtil(ServiceRequestRepository serviceRequestRepository, Configuration config, ObjectMapper mapper, FilestoreUtil filestoreUtil, ParsingUtil parsingUtil) { @@ -58,6 +36,50 @@ public CampaignIntegrationUtil(ServiceRequestRepository serviceRequestRepository this.serviceRequestRepository = serviceRequestRepository; this.config = config; this.mapper = mapper; + this.parsingUtil= parsingUtil; + } + + /** + * Updates resources in the Project Factory by calling an external API with the given plan configuration + * request and file store ID. Logs the operation status. + * + * @param planConfigurationRequest The plan configuration request details. + * @param fileStoreId The file store ID to update. + * @throws CustomException if the API call fails. + */ + public void updateResourcesInProjectFactory(PlanConfigurationRequest planConfigurationRequest, String fileStoreId) { + try { + serviceRequestRepository.fetchResult( + new StringBuilder(config.getProjectFactoryHostEndPoint() + config.getCampaignIntegrationFetchFromMicroplanEndPoint()), + buildMicroplanDetailsForUpdate(planConfigurationRequest, fileStoreId)); + log.info("Updated resources file into project factory - " + fileStoreId); + } catch (Exception e) { + log.error(ERROR_WHILE_CALLING_MICROPLAN_API + planConfigurationRequest.getPlanConfiguration().getId(), e); + throw new CustomException(ERROR_WHILE_CALLING_MICROPLAN_API, e.toString()); + } + + } + + /** + * 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 fileStoreId The filestoreId with calculated resources + * @return The microplan details request object built for updating resource filestore id. + */ + private MicroplanDetailsRequest buildMicroplanDetailsForUpdate(PlanConfigurationRequest planConfigurationRequest, String fileStoreId) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + + MicroplanDetails microplanDetails = MicroplanDetails.builder() + .tenantId(planConfig.getTenantId()) + .planConfigurationId(planConfig.getId()) + .campaignId(planConfig.getCampaignId()) + .resourceFilestoreId(fileStoreId).build(); + + return MicroplanDetailsRequest.builder() + .microplanDetails(microplanDetails) + .requestInfo(planConfigurationRequest.getRequestInfo()).build(); + } /** @@ -83,7 +105,28 @@ public void updateCampaignDetails(PlanConfigurationRequest planConfigurationRequ log.info("Campaign Integration successful."); } catch (Exception e) { log.error(ServiceConstants.ERROR_WHILE_SEARCHING_CAMPAIGN - + planConfigurationRequest.getPlanConfiguration().getExecutionPlanId(), e); + + planConfigurationRequest.getPlanConfiguration().getCampaignId(), e); + throw new CustomException("Failed to update campaign details in CampaignIntegration class within method updateCampaignDetails.", e.toString()); + } + } + + /** + * Sends a data creation request to the Project Factory service using the provided + * plan and campaign details. + * + * @param planConfigurationRequest the plan configuration request containing campaign data + * @param campaignResponse the response with additional campaign information + * @throws CustomException if the data creation call fails + */ + public void createProjectFactoryDataCall(PlanConfigurationRequest planConfigurationRequest, CampaignResponse campaignResponse) { + try { + serviceRequestRepository.fetchResult( + new StringBuilder(config.getProjectFactoryHostEndPoint() + config.getCampaignIntegrationDataCreateEndPoint()), + buildResourceDetailsObjectForFacilityCreate(planConfigurationRequest, campaignResponse)); + log.info("Campaign Data create successful."); + } catch (Exception e) { + log.error(ServiceConstants.ERROR_WHILE_DATA_CREATE_CALL + + planConfigurationRequest.getPlanConfiguration().getCampaignId(), e); throw new CustomException("Failed to update campaign details in CampaignIntegration class within method updateCampaignDetails.", e.toString()); } } @@ -123,6 +166,42 @@ private CampaignRequest buildCampaignRequestForUpdate(PlanConfigurationRequest p } + /** + * Builds a {@link ResourceDetailsRequest} object for facility creation using the provided + * plan configuration and campaign details. + * + * @param planConfigurationRequest the request containing plan configuration data + * @param campaignResponse the campaign response with additional data + * @return a {@link ResourceDetailsRequest} for facility creation + * @throws CustomException if the required facility file is not found + */ + private ResourceDetailsRequest buildResourceDetailsObjectForFacilityCreate(PlanConfigurationRequest planConfigurationRequest, + CampaignResponse campaignResponse) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + + String facilityFilestoreId = String.valueOf(planConfig.getFiles().stream() + .filter(file -> FILE_TEMPLATE_IDENTIFIER_FACILITY.equals(file.getTemplateIdentifier())) + .map(File::getFilestoreId) + .findFirst() + .orElseThrow(() -> new CustomException(FILE_NOT_FOUND_CODE, FILE_NOT_FOUND_MESSAGE + FILE_TEMPLATE_IDENTIFIER_FACILITY))); + + ResourceDetails resourceDetails = ResourceDetails.builder() + .type(TYPE_FACILITY) + .hierarchyType(campaignResponse.getCampaign().get(0).getHierarchyType()) + .tenantId(planConfig.getTenantId()) + .fileStoreId(facilityFilestoreId) + .action(ACTION_CREATE) + .campaignId(planConfig.getCampaignId()) + .additionalDetails(createAdditionalDetailsforFacilityCreate(MICROPLAN_SOURCE_KEY, planConfig.getId())) + .build(); + + return ResourceDetailsRequest.builder() + .requestInfo(planConfigurationRequest.getRequestInfo()) + .resourceDetails(resourceDetails) + .build(); + + } + /** * Updates campaign boundary based on the provided plan configuration, feature, assumption values, mapped values, column index map, boundary list, and result map. * @@ -143,29 +222,13 @@ public void updateCampaignBoundary(PlanConfiguration planConfig, JsonNode featur boolean validToAdd = false; Integer indexValue = 0; Boundary boundary = new Boundary(); - List> sortedColumnList = sortColumnByIndex(mapOfColumnNameAndIndex); - indexValue = getIndexOfBoundaryCode(indexValue, sortedColumnList, mappedValues); + List> sortedColumnList = parsingUtil.sortColumnByIndex(mapOfColumnNameAndIndex); + indexValue = parsingUtil.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. @@ -219,22 +282,7 @@ private boolean isValidToAdd(List boundaryList, Map> 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. @@ -279,9 +327,35 @@ public CampaignSearchRequest buildCampaignRequestForSearch(PlanConfigurationRequ PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); List id = new ArrayList(); - id.add(planConfig.getExecutionPlanId()); + id.add(planConfig.getCampaignId()); return CampaignSearchRequest.builder().requestInfo(planConfigurationRequest.getRequestInfo()) .campaignDetails(CampaignDetails.builder().ids(id).tenantId(planConfig.getTenantId()).build()).build(); } + + /** + * 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. + */ + public CampaignResponse parseCampaignResponse(Object campaignResponse) { + CampaignResponse campaign = null; + campaign = mapper.convertValue(campaignResponse, CampaignResponse.class); + return campaign; + } + + public JsonNode createAdditionalDetailsforFacilityCreate(String source, String microplanId) { + try { + // Create a map to hold the additional details + Map additionalDetailsMap = new HashMap<>(); + additionalDetailsMap.put(SOURCE_KEY, source); + additionalDetailsMap.put(MICROPLAN_ID_KEY, microplanId); + + // Convert the map to a JsonNode + return mapper.valueToTree(additionalDetailsMap); + } catch (Exception e) { + throw new CustomException(UNABLE_TO_CREATE_ADDITIONAL_DETAILS_CODE, UNABLE_TO_CREATE_ADDITIONAL_DETAILS_MESSAGE);// Or throw a custom exception + } + } } diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/CensusUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/CensusUtil.java new file mode 100644 index 00000000000..2e79ff60af5 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/CensusUtil.java @@ -0,0 +1,191 @@ +package org.egov.processor.util; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.models.Workflow; +import org.egov.processor.config.Configuration; +import org.egov.processor.config.ServiceConstants; +import org.egov.processor.kafka.Producer; +import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.census.*; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static org.egov.processor.config.ServiceConstants.*; + +@Component +@Slf4j +public class CensusUtil { + + private ServiceRequestRepository serviceRequestRepository; + + private Configuration config; + + private Producer producer; + + private ParsingUtil parsingUtil; + + private ObjectMapper mapper; + + public CensusUtil(ServiceRequestRepository serviceRequestRepository, Configuration config, Producer producer, ParsingUtil parsingUtil, ObjectMapper objectMapper) { + this.serviceRequestRepository = serviceRequestRepository; + this.config = config; + this.producer = producer; + this.parsingUtil = parsingUtil; + this.mapper = objectMapper; + } + + /** + * Creates and pushes a CensusRequest based on the provided plan configuration, feature JSON node, and mapped values. + * + * @param planConfigurationRequest The plan configuration request with the necessary details. + * @param feature The JSON node containing feature data for the census. + * @param mappedValues A map of property names to their values from the feature node. + * @param heirarchyType The type of hierarchy to be used in the census. + */ + public void create(PlanConfigurationRequest planConfigurationRequest, JsonNode feature, Map mappedValues, String heirarchyType) { + CensusRequest censusRequest = buildCensusRequest(planConfigurationRequest, feature, mappedValues, heirarchyType); + try { + log.info("Census request - " + censusRequest.getCensus()); + producer.push(config.getResourceCensusCreateTopic(), censusRequest); + } catch (Exception e) { + log.error(ERROR_WHILE_PUSHING_TO_PLAN_SERVICE_FOR_LOCALITY + censusRequest.getCensus().getBoundaryCode(), e); + } + } + + /** + * Builds and returns a CensusRequest using the provided plan configuration, feature JSON node, and mapped values. + * + * @param planConfigurationRequest The plan configuration request containing configuration details. + * @param feature The feature JSON node containing property values. + * @param mappedValues The mapped values for extracting properties. + * @param heirarchyType The hierarchy type of the census. + * @return A constructed CensusRequest object with populated details. + */ + private CensusRequest buildCensusRequest(PlanConfigurationRequest planConfigurationRequest, JsonNode feature, Map mappedValues, String heirarchyType) { + + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + return CensusRequest.builder() + .census(Census.builder() + .tenantId(planConfig.getTenantId()) + .hierarchyType(heirarchyType) + .boundaryCode((String) parsingUtil.extractMappedValueFromFeatureForAnInput(ServiceConstants.BOUNDARY_CODE, feature, mappedValues)) + .type(Census.TypeEnum.PEOPLE) + .facilityAssigned(Boolean.FALSE) + .partnerAssignmentValidationEnabled(Boolean.TRUE) + .totalPopulation((BigDecimal) parsingUtil.extractMappedValueFromFeatureForAnInput(ServiceConstants.TOTAL_POPULATION, feature, mappedValues)) + .workflow(Workflow.builder().action(WORKFLOW_ACTION_INITIATE).build()) + .source(planConfig.getId()) + .additionalFields(enrichAdditionalField(feature, mappedValues)).build()) + .requestInfo(planConfigurationRequest.getRequestInfo()).build(); + + } + + /** + * Enriches and returns additional details by extracting values from the feature JSON node based on the provided mappings. + * + * @param feature The feature JSON node containing property values. + * @param mappedValues The mapped values for extracting properties. + * @return A map containing enriched additional details based on the extracted values. + */ + public List enrichAdditionalField(JsonNode feature, Map mappedValues) { + // Initialize orderCounter inside the function + List additionalFieldList = new ArrayList<>(); + int orderCounter = 1; + + for (String key : mappedValues.keySet()) { + // Skip keys in the override list + if (config.getCensusAdditionalFieldOverrideKeys().contains(key)) + continue; + + // Get the corresponding value from the feature JsonNode + Object valueFromRow = parsingUtil.extractMappedValueFromFeatureForAnInput(key, feature, mappedValues); + + // Check if the value exists in the JSON + if (!ObjectUtils.isEmpty(valueFromRow)) { + // Add additional fields with "UPLOADED" and "CONFIRMED" prefixes if key is in override list + if (config.getCensusAdditionalPrefixAppendKeys().contains(key)) { + AdditionalField uploadedField = AdditionalField.builder() + .key(UPLOADED_KEY + key) + .value((BigDecimal) valueFromRow) + .editable(Boolean.FALSE) + .showOnUi(Boolean.TRUE) + .order(orderCounter++) // Increment for "UPLOADED" field + .build(); + additionalFieldList.add(uploadedField); + + AdditionalField confirmedField = AdditionalField.builder() + .key(CONFIRMED_KEY + key) + .value((BigDecimal) valueFromRow) + .editable(Boolean.TRUE) + .showOnUi(Boolean.TRUE) + .order(orderCounter++) // Increment for "CONFIRMED" field + .build(); + additionalFieldList.add(confirmedField); + } else { + AdditionalField additionalField = AdditionalField.builder() + .key(key) + .value((BigDecimal) valueFromRow) + .order(orderCounter++) // Use and increment the local orderCounter + .build(); + if(config.getCensusAdditionalFieldShowOnUIFalseKeys().contains(key)) { + additionalField.setShowOnUi(Boolean.FALSE); + additionalField.setEditable(Boolean.FALSE); + } else { + additionalField.setShowOnUi(Boolean.TRUE); + additionalField.setEditable(Boolean.TRUE); + } + additionalFieldList.add(additionalField); + } + } + } + + return additionalFieldList; + } + + /** + * This method fetches data from Census based on the given census search request. + * + * @param searchRequest The census search request containing the search criteria. + * @return returns the census response. + */ + public CensusResponse fetchCensusRecords(CensusSearchRequest searchRequest) { + + // Get census search uri + String uri = getCensusUri().toString(); + + CensusResponse censusResponse = null; + try { + Object response = serviceRequestRepository.fetchResult(new StringBuilder(uri), searchRequest); + censusResponse = mapper.convertValue(response, CensusResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_CENSUS, e); + } + + if (CollectionUtils.isEmpty(censusResponse.getCensus())) { + throw new CustomException(NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_CODE, NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_MESSAGE); + } + + return censusResponse; + } + + /** + * Builds the census search uri. + * + * @return returns the complete uri for census search. + */ + private StringBuilder getCensusUri() { + return new StringBuilder().append(config.getCensusHost()).append(config.getCensusSearchEndPoint()); + } + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java new file mode 100644 index 00000000000..89f0a89511b --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/EnrichmentUtil.java @@ -0,0 +1,297 @@ +package org.egov.processor.util; + +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.egov.common.utils.UUIDEnrichmentUtil; +import org.egov.processor.config.Configuration; +import org.egov.processor.web.PlanResponse; +import org.egov.processor.web.PlanSearchCriteria; +import org.egov.processor.web.PlanSearchRequest; +import org.egov.processor.web.models.*; +import org.egov.processor.web.models.census.Census; +import org.egov.processor.web.models.census.CensusResponse; +import org.egov.processor.web.models.census.CensusSearchCriteria; +import org.egov.processor.web.models.census.CensusSearchRequest; +import org.egov.processor.web.models.mdmsV2.Mdms; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.processor.config.ServiceConstants.*; + +@Component +@Slf4j +public class EnrichmentUtil { + + private MdmsV2Util mdmsV2Util; + + private LocaleUtil localeUtil; + + private ParsingUtil parsingUtil; + + private CensusUtil censusUtil; + + private PlanUtil planUtil; + + private Configuration config; +// private MultiStateInstanceUtil centralInstanceUtil; + + public EnrichmentUtil(MdmsV2Util mdmsV2Util, LocaleUtil localeUtil, ParsingUtil parsingUtil, CensusUtil censusUtil, PlanUtil planUtil, Configuration config) { + this.mdmsV2Util = mdmsV2Util; + this.localeUtil = localeUtil; +// this.centralInstanceUtil = centralInstanceUtil; + this.parsingUtil = parsingUtil; + this.censusUtil = censusUtil; + this.planUtil = planUtil; + this.config = config; + } + + /** + * Enriches the `PlanConfiguration` with resource mappings based on MDMS data and locale messages. + * + * @param request The request containing the configuration to enrich. + * @param localeResponse The response containing locale messages. + * @param campaignType The campaign type identifier. + * @param fileStoreId The associated file store ID. + */ + public void enrichResourceMapping(PlanConfigurationRequest request, LocaleResponse localeResponse, String campaignType, String fileStoreId) + { +// String rootTenantId = centralInstanceUtil.getStateLevelTenant(request.getPlanConfiguration().getTenantId()); + String rootTenantId = request.getPlanConfiguration().getTenantId().split("\\.")[0]; + String uniqueIndentifier = BOUNDARY + DOT_SEPARATOR + MICROPLAN_PREFIX + campaignType; + List mdmsV2Data = mdmsV2Util.fetchMdmsV2Data(request.getRequestInfo(), rootTenantId, MDMS_ADMIN_CONSOLE_MODULE_NAME + DOT_SEPARATOR + MDMS_SCHEMA_ADMIN_SCHEMA, uniqueIndentifier); + List columnNameList = parsingUtil.extractPropertyNamesFromAdminSchema(mdmsV2Data.get(0).getData()); + + List resourceMappingList = new ArrayList<>(); + for(String columnName : columnNameList) { + ResourceMapping resourceMapping = ResourceMapping + .builder() + .filestoreId(fileStoreId) + .mappedTo(columnName) + .active(Boolean.TRUE) + .mappedFrom(localeUtil.localeSearch(localeResponse.getMessages(), columnName)) + .build(); + UUIDEnrichmentUtil.enrichRandomUuid(resourceMapping, "id"); + resourceMappingList.add(resourceMapping); + } + + //enrich plan configuration with enriched resource mapping list + request.getPlanConfiguration().setResourceMapping(resourceMappingList); + + } + + public void enrichsheetWithApprovedCensusRecords(Sheet sheet, PlanConfigurationRequest planConfigurationRequest, String fileStoreId, Map mappedValues) { + List boundaryCodes = getBoundaryCodesFromTheSheet(sheet, planConfigurationRequest, fileStoreId); + + Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); + Integer indexOfBoundaryCode = parsingUtil.getIndexOfBoundaryCode(0, + parsingUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); + + //Getting census records for the list of boundaryCodes + List censusList = getCensusRecordsForEnrichment(planConfigurationRequest, boundaryCodes); + + // Create a map from boundaryCode to Census for quick lookups + Map censusMap = censusList.stream() + .collect(Collectors.toMap(Census::getBoundaryCode, census -> census)); + + + for(Row row: sheet) { + parsingUtil.printRow(sheet, row); + // Skip the header row and empty rows + if (row.getRowNum() == 0 || parsingUtil.isRowEmpty(row)) { + continue; + } + + // Get the boundaryCode in the current row + Cell boundaryCodeCell = row.getCell(indexOfBoundaryCode); + String boundaryCode = boundaryCodeCell.getStringCellValue(); + + Census census = censusMap.get(boundaryCode); + + if (census != null) { + // For each field in the sheetToCensusMap, update the cell if the field is editable + for (Map.Entry entry : mappedValues.entrySet()) { + String censusKey = entry.getKey(); + String sheetColumn = entry.getValue(); + + if(config.getCensusAdditionalFieldOverrideKeys().contains(censusKey)) + continue; + censusKey = config.getCensusAdditionalPrefixAppendKeys().contains(censusKey) ? CONFIRMED_KEY + censusKey : censusKey; + + // Get the column index from the mapOfColumnNameAndIndex + Integer columnIndex = mapOfColumnNameAndIndex.get(sheetColumn); + if (columnIndex != null) { + // Get the value for this field in the census, if editable + BigDecimal editableValue = getEditableValue(census, censusKey); + + if(ObjectUtils.isEmpty(editableValue)) continue; + + Cell cell = row.getCell(columnIndex); + if (cell == null) { + cell = row.createCell(columnIndex); + } + cell.setCellValue(editableValue.doubleValue()); + + } + } + } + + log.info("Successfully update file with approved census data."); + } + } + + public List getBoundaryCodesFromTheSheet(Sheet sheet, PlanConfigurationRequest planConfigurationRequest, String fileStoreId) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + + Map mappedValues = planConfig.getResourceMapping().stream() + .filter(f -> f.getFilestoreId().equals(fileStoreId)) + .collect(Collectors.toMap(ResourceMapping::getMappedTo, ResourceMapping::getMappedFrom)); + + Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); + + Integer indexOfBoundaryCode = parsingUtil.getIndexOfBoundaryCode(0, + parsingUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); + + List boundaryCodes = new ArrayList<>(); + + for (Row row : sheet) { + // Skip the header row and empty rows + if (row.getRowNum() == 0 || parsingUtil.isRowEmpty(row)) { + continue; + } + + // Get the boundary code cell + Cell boundaryCodeCell = row.getCell(indexOfBoundaryCode); + + // Check if the cell is non-empty and collect its value + if (boundaryCodeCell != null && boundaryCodeCell.getCellType() == CellType.STRING) { + String boundaryCode = boundaryCodeCell.getStringCellValue().trim(); + if (!boundaryCode.isEmpty()) { + boundaryCodes.add(boundaryCode); + } + } + } + + return boundaryCodes; + } + + public List getCensusRecordsForEnrichment(PlanConfigurationRequest planConfigurationRequest, List boundaryCodes) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + CensusSearchCriteria censusSearchCriteria = CensusSearchCriteria.builder() + .tenantId(planConfig.getTenantId()) + .areaCodes(boundaryCodes) + .limit(boundaryCodes.size()) + .source(planConfig.getId()).build(); + + CensusSearchRequest censusSearchRequest = CensusSearchRequest.builder() + .censusSearchCriteria(censusSearchCriteria) + .requestInfo(planConfigurationRequest.getRequestInfo()).build(); + + CensusResponse censusResponse = censusUtil.fetchCensusRecords(censusSearchRequest); + + if(censusResponse.getCensus().isEmpty()) + throw new CustomException(NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_CODE, NO_CENSUS_FOUND_FOR_GIVEN_DETAILS_MESSAGE); + + return censusResponse.getCensus(); + + } + + private BigDecimal getEditableValue(Census census, String key) { + return census.getAdditionalFields().stream() + .filter(field -> field.getEditable() && key.equals(field.getKey())) // Filter by editability and matching key + .map(field -> field.getValue()) + .findFirst() + .orElse(null); + } + + public void enrichsheetWithApprovedPlanEstimates(Sheet sheet, PlanConfigurationRequest planConfigurationRequest, String fileStoreId, Map mappedValues) { + List boundaryCodes = getBoundaryCodesFromTheSheet(sheet, planConfigurationRequest, fileStoreId); + + Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); + Integer indexOfBoundaryCode = parsingUtil.getIndexOfBoundaryCode(0, + parsingUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); + + //Getting census records for the list of boundaryCodes + List planList = getPlanRecordsForEnrichment(planConfigurationRequest, boundaryCodes); + + // Create a map from boundaryCode to Census for quick lookups + Map planMap = planList.stream() + .collect(Collectors.toMap(Plan::getLocality, plan -> plan)); + + List outputColumnList = planList.get(0).getResources().stream() + .map(Resource::getResourceType) + .toList(); + + + for(Row row: sheet) { + // Skip the header row and empty rows + if (row.getRowNum() == 0 || parsingUtil.isRowEmpty(row)) { + continue; + } + // Get the boundaryCode in the current row + Cell boundaryCodeCell = row.getCell(indexOfBoundaryCode); + String boundaryCode = boundaryCodeCell.getStringCellValue(); + + Plan planEstimate = planMap.get(boundaryCode); + + if (planEstimate != null) { + Map resourceTypeToEstimatedNumberMap = planEstimate.getResources().stream() + .collect(Collectors.toMap(Resource::getResourceType, Resource::getEstimatedNumber)); + + // Iterate over each output column to update the row cells with resource values + for (String resourceType : outputColumnList) { + BigDecimal estimatedValue = resourceTypeToEstimatedNumberMap.get(resourceType); + + if (estimatedValue != null) { + // Get the index of the column to update + Integer columnIndex = mapOfColumnNameAndIndex.get(resourceType); + if (columnIndex != null) { + // Update the cell with the resource value + Cell cell = row.getCell(columnIndex); + if (cell == null) { + cell = row.createCell(columnIndex); + } + cell.setCellValue(estimatedValue.doubleValue()); + } + } + } + } + + log.info("Successfully update file with approved census data."); + } + } + + + public List getPlanRecordsForEnrichment(PlanConfigurationRequest planConfigurationRequest, List boundaryCodes) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + PlanSearchCriteria planSearchCriteria = PlanSearchCriteria.builder() + .tenantId(planConfig.getTenantId()) + .locality(boundaryCodes) + .limit(boundaryCodes.size()) + .planConfigurationId(planConfig.getId()).build(); + + PlanSearchRequest planSearchRequest = PlanSearchRequest.builder() + .planSearchCriteria(planSearchCriteria) + .requestInfo(planConfigurationRequest.getRequestInfo()).build(); + + PlanResponse planResponse = planUtil.search(planSearchRequest); + + if(planResponse.getPlan().isEmpty()) + throw new CustomException(NO_PLAN_FOUND_FOR_GIVEN_DETAILS_CODE, NO_PLAN_FOUND_FOR_GIVEN_DETAILS_MESSAGE); + + return planResponse.getPlan(); + } + + + + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/FilestoreUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/FilestoreUtil.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/util/FilestoreUtil.java rename to health-services/resource-generator/src/main/java/org/egov/processor/util/FilestoreUtil.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/LocaleUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/LocaleUtil.java similarity index 89% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/util/LocaleUtil.java rename to health-services/resource-generator/src/main/java/org/egov/processor/util/LocaleUtil.java index 1ecb725308f..12fefec0405 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/LocaleUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/LocaleUtil.java @@ -5,12 +5,9 @@ import org.egov.processor.config.Configuration; import org.egov.processor.config.ServiceConstants; import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.processor.web.models.Locale; 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; @@ -71,10 +68,19 @@ public LocaleResponse searchLocale(PlanConfigurationRequest planConfigurationReq log.info("Locale Search successful."); return localeResponse; } catch (Exception e) { - log.error(ServiceConstants.ERROR_WHILE_SEARCHING_LOCALE + localeToUse + " and tenantId" + tenantId, 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, + ServiceConstants.ERROR_WHILE_SEARCHING_LOCALE + localeToUse + " and tenantId " + tenantId, e.toString()); } } + + public String localeSearch(List localeMessages, String code) { + for (Locale locale : localeMessages) { + if (locale.getCode().equalsIgnoreCase(code)) { + return locale.getMessage(); // Return the message if code matches + } + } + return null; + } } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/MdmsUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/MdmsUtil.java similarity index 99% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/util/MdmsUtil.java rename to health-services/resource-generator/src/main/java/org/egov/processor/util/MdmsUtil.java index 229dbf57f45..e3019ded61b 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/MdmsUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/MdmsUtil.java @@ -132,7 +132,7 @@ public Map filterMasterData(String masterDataJson, File.InputFil 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) + if (schema.get(ServiceConstants.MDMS_SCHEMA_SECTION).equals(ServiceConstants.FILE_TEMPLATE_IDENTIFIER_POPULATION) && campaign.equals(campaignType) && type.equals(fileType.toString())) { Map schemaProperties = (Map) schema.get("schema"); properties = (Map) schemaProperties.get("Properties"); diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/util/MdmsV2Util.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/MdmsV2Util.java new file mode 100644 index 00000000000..85b87872658 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/MdmsV2Util.java @@ -0,0 +1,79 @@ +package org.egov.processor.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.processor.config.Configuration; +import org.egov.processor.web.models.mdmsV2.Mdms; +import org.egov.processor.web.models.mdmsV2.MdmsCriteriaReqV2; +import org.egov.processor.web.models.mdmsV2.MdmsCriteriaV2; +import org.egov.processor.web.models.mdmsV2.MdmsResponseV2; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.web.client.RestTemplate; + +import java.util.Collections; +import java.util.List; + +import static org.egov.processor.config.ServiceConstants.*; + +@Slf4j +@Component +public class MdmsV2Util { + + private RestTemplate restTemplate; + + private ObjectMapper objectMapper; + + private Configuration config; + + public MdmsV2Util(RestTemplate restTemplate, ObjectMapper objectMapper, Configuration config) + { + this.restTemplate = restTemplate; + this.objectMapper = objectMapper; + this.config = config; + } + + public List fetchMdmsV2Data(RequestInfo requestInfo, String tenantId, String schemaCode, String uniqueIdentifier) + { + StringBuilder uri = getMdmsV2Uri(); + MdmsCriteriaReqV2 mdmsCriteriaReqV2 = getMdmsV2Request(requestInfo, tenantId, schemaCode, uniqueIdentifier); + MdmsResponseV2 mdmsResponseV2 = null; + try { + mdmsResponseV2 = restTemplate.postForObject(uri.toString(), mdmsCriteriaReqV2, MdmsResponseV2.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_MDMS, e); + } + + if(ObjectUtils.isEmpty(mdmsResponseV2.getMdms())) + { + 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 mdmsResponseV2.getMdms(); + } + + private StringBuilder getMdmsV2Uri() + { + StringBuilder uri = new StringBuilder(); + return uri.append(config.getMdmsHost()).append(config.getMdmsV2EndPoint()); + } + + private MdmsCriteriaReqV2 getMdmsV2Request(RequestInfo requestInfo, String tenantId, String schemaCode, String uniqueIdentifier) + { + MdmsCriteriaV2 mdmsCriteriaV2 = MdmsCriteriaV2.builder() + .tenantId(tenantId) + .schemaCode(schemaCode) + .uniqueIdentifiers(Collections.singletonList(uniqueIdentifier)) + .limit(config.getDefaultLimit()) + .offset(config.getDefaultOffset()).build(); + + return MdmsCriteriaReqV2.builder() + .requestInfo(requestInfo) + .mdmsCriteriaV2(mdmsCriteriaV2).build(); + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/ParsingUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java similarity index 59% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/util/ParsingUtil.java rename to health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java index b1902b49afb..ba10327e4c8 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/ParsingUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/ParsingUtil.java @@ -1,38 +1,30 @@ package org.egov.processor.util; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.DecimalNode; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.apache.poi.ss.usermodel.*; +import org.egov.processor.config.ServiceConstants; +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 org.springframework.util.ObjectUtils; + 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.*; 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; +import static org.egov.processor.config.ServiceConstants.PROPERTIES; @Slf4j @Component @@ -63,6 +55,8 @@ public List fetchAttributeNamesFromJson(JsonNode jsonNode) } return columnNames; } + + public void validateColumnNames(List columnNamesList, PlanConfiguration planConfig, String fileStoreId ) { Set mappedFromSet = planConfig.getResourceMapping().stream() .filter(mapping -> Objects.equals(mapping.getFilestoreId(), fileStoreId)) @@ -99,12 +93,40 @@ public Map getAttributeNameIndexFromExcel(Sheet sheet) { 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 columnIndexMap; + } + + /** + * Retrieves the mapped value from the feature JSON node using the mapped value for the given input, + * returning it as the appropriate data type. + * + * @param input The input value. + * @param feature The feature JSON node. + * @param mappedValues The mapped values. + * @return The value of the corresponding data type (Long, String, Boolean, etc.). + * @throws CustomException if the input value is not found in the feature JSON node or if the value type is unsupported. + */ + public Object extractMappedValueFromFeatureForAnInput(String input, JsonNode feature, Map mappedValues) { + // Get the value as a JsonNode, not a String + JsonNode mappedValueNode = feature.get(PROPERTIES).get(mappedValues.get(input)); + + // Check if the value exists in the JSON + if (!ObjectUtils.isEmpty(mappedValueNode)) { + + // Now return the value based on its actual type in the JsonNode + if (mappedValueNode instanceof DecimalNode) { + return ((DecimalNode) mappedValueNode).decimalValue(); // Returns BigDecimal + } else if (mappedValueNode.isBoolean()) { + return mappedValueNode.asBoolean(); + } else if (mappedValueNode.isTextual()) { + return mappedValueNode.asText(); + } else { + return null; + } + } + else { + return null; } - return sortedMap; } /** @@ -246,4 +268,128 @@ public File extractShapeFilesFromZip(PlanConfiguration planConfig, String fileSt return shpFile; } + /** + * Extracts the names of properties defined within the "numberProperties" and "stringProperties" arrays from admin schema + * + * @param rootNode The root JSON node from which to extract property names. + * @return A list of property names found in "numberProperties" and "stringProperties". + */ + public List extractPropertyNamesFromAdminSchema(JsonNode rootNode) { + List names = new ArrayList<>(); + + // Access the "properties" node directly from the root node + JsonNode propertiesNode = rootNode.path("properties"); + + // Extract names from "numberProperties" + JsonNode numberProperties = propertiesNode.path("numberProperties"); + if (numberProperties.isArray()) { + for (JsonNode property : numberProperties) { + String name = property.path("name").asText(null); + if (name != null) { + names.add(name); + } + } + } + + // Extract names from "stringProperties" + JsonNode stringProperties = propertiesNode.path("stringProperties"); + if (stringProperties.isArray()) { + for (JsonNode property : stringProperties) { + String name = property.path("name").asText(null); + if (name != null) { + names.add(name); + } + } + } + + return names; + } + + + /** + * 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; + } + + /** + * 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; + } + + /** + * 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; + } + + public void printRow(Sheet sheet, Row row) { + System.out.print("Row -> "); + for (Cell cell : row) { + int columnIndex = cell.getColumnIndex(); + 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 + } + } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java similarity index 85% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java rename to health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java index 26a11dcf976..55a8651ec56 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java @@ -1,19 +1,17 @@ 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.egov.processor.web.models.*; import org.springframework.stereotype.Component; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; + import static org.egov.processor.config.ServiceConstants.ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE; @Component @@ -54,4 +52,8 @@ public List search(PlanConfigurationSearchRequest planConfigu else return planConfigurationList; } + + public void orderPlanConfigurationOperations(PlanConfigurationRequest planConfigurationRequest) { + planConfigurationRequest.getPlanConfiguration().getOperations().sort(Comparator.comparingInt(Operation::getExecutionOrder)); + } } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanUtil.java b/health-services/resource-generator/src/main/java/org/egov/processor/util/PlanUtil.java similarity index 70% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanUtil.java rename to health-services/resource-generator/src/main/java/org/egov/processor/util/PlanUtil.java index d44aaa2a59f..97c9810e0c5 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanUtil.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/util/PlanUtil.java @@ -1,33 +1,26 @@ 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 com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.models.Workflow; 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.processor.repository.ServiceRequestRepository; +import org.egov.processor.web.PlanResponse; +import org.egov.processor.web.PlanSearchRequest; +import org.egov.processor.web.models.*; import org.egov.tracer.model.CustomException; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Map; +import java.util.stream.Collectors; -import lombok.extern.slf4j.Slf4j; +import static org.egov.processor.config.ServiceConstants.*; @Component @Slf4j @@ -38,11 +31,14 @@ public class PlanUtil { private Producer producer; - public PlanUtil(ServiceRequestRepository serviceRequestRepository, Configuration config, Producer producer) { + private ObjectMapper mapper; + + public PlanUtil(ServiceRequestRepository serviceRequestRepository, Configuration config, Producer producer, ObjectMapper mapper) { this.serviceRequestRepository = serviceRequestRepository; this.config = config; this.producer = producer; - } + this.mapper = mapper; + } /** * Creates a plan configuration request, builds a plan request from it, and pushes it to the messaging system for further processing. @@ -55,7 +51,7 @@ public PlanUtil(ServiceRequestRepository serviceRequestRepository, Configuration public void create(PlanConfigurationRequest planConfigurationRequest, JsonNode feature, Map resultMap, Map mappedValues) { PlanRequest planRequest = buildPlanRequest(planConfigurationRequest, feature, resultMap, mappedValues); - try { + try { producer.push(config.getResourceMicroplanCreateTopic(), planRequest); } catch (Exception e) { log.error(ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE_FOR_LOCALITY + planRequest.getPlan().getLocality(), e); @@ -80,7 +76,8 @@ private PlanRequest buildPlanRequest(PlanConfigurationRequest planConfigurationR .requestInfo(planConfigurationRequest.getRequestInfo()) .plan(Plan.builder() .tenantId(planConfig.getTenantId()) - .executionPlanId(planConfig.getExecutionPlanId()) + .planConfigurationId(planConfig.getId()) + .campaignId(planConfig.getCampaignId()) .locality(getBoundaryCodeValue(ServiceConstants.BOUNDARY_CODE, feature, mappedValues)) .resources(resultMap.entrySet().stream().map(result -> { @@ -91,6 +88,8 @@ private PlanRequest buildPlanRequest(PlanConfigurationRequest planConfigurationR }).collect(Collectors.toList())) .activities(new ArrayList()) .targets(new ArrayList()) + .workflow(Workflow.builder().action(WORKFLOW_ACTION_INITIATE).build()) + .isRequestFromResourceEstimationConsumer(true) .build()) .build(); @@ -124,9 +123,42 @@ public void update(PlanConfigurationRequest planConfigurationRequest) { try { producer.push(config.getResourceUpdatePlanConfigConsumerTopic(), planConfigurationRequest); - log.info("Plan Config updated because of Invalid data."); + log.info("Plan Config updated after processing."); } catch (Exception e) { log.error(ServiceConstants.ERROR_WHILE_UPDATING_PLAN_CONFIG); } } + + + public PlanResponse search(PlanSearchRequest planSearchRequest) { + + PlanResponse planResponse = null; + try { + Object response = serviceRequestRepository.fetchResult(getPlanSearchUri(), planSearchRequest); + planResponse = mapper.convertValue(response, PlanResponse.class); + } catch (Exception e) { + log.error(ServiceConstants.ERROR_WHILE_SEARCHING_PLAN); + } + + if (CollectionUtils.isEmpty(planResponse.getPlan())) { + throw new CustomException(NO_PLAN_FOUND_FOR_GIVEN_DETAILS_CODE, NO_PLAN_FOUND_FOR_GIVEN_DETAILS_MESSAGE); + } + + return planResponse; + } + + private StringBuilder getPlanSearchUri() { + return new StringBuilder().append(config.getPlanConfigHost()).append(config.getPlanSearchEndPoint()); + } + + public void setFileStoreIdForPopulationTemplate(PlanConfigurationRequest planConfigurationRequest, String fileStoreId) { + planConfigurationRequest.getPlanConfiguration().getFiles().stream() + .filter(file -> FILE_TEMPLATE_IDENTIFIER_POPULATION.equals(file.getTemplateIdentifier())) + .findFirst() + .ifPresent(file -> file.setFilestoreId(fileStoreId)); + + planConfigurationRequest.getPlanConfiguration().setWorkflow(null); + } + + } diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/PlanResponse.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/PlanResponse.java new file mode 100644 index 00000000000..5f4fc7b1882 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/PlanResponse.java @@ -0,0 +1,42 @@ +package org.egov.processor.web; + +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.response.ResponseInfo; +import org.egov.processor.web.models.Plan; +import org.springframework.validation.annotation.Validated; + +import java.util.List; +import java.util.Map; + +/** + * PlanSearchResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Plan") + @Valid + private List plan = null; + + @JsonProperty("TotalCount") + @Valid + private Integer totalCount = null; + + @JsonProperty("StatusCount") + @Valid + private Map statusCount = null; + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/PlanSearchCriteria.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/PlanSearchCriteria.java new file mode 100644 index 00000000000..eec1a370b39 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/PlanSearchCriteria.java @@ -0,0 +1,57 @@ +package org.egov.processor.web; + +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 java.util.List; +import java.util.Set; + +/** + * PlanSearchCriteria + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanSearchCriteria { + + @JsonProperty("ids") + private Set ids = null; + + @JsonProperty("tenantId") + @NotNull + private String tenantId = null; + + @JsonProperty("locality") + private List locality = null; + + @JsonProperty("campaignId") + private String campaignId = null; + + @JsonProperty("planConfigurationId") + private String planConfigurationId = null; + + @JsonProperty("status") + private String status = null; + + @JsonProperty("assignee") + private String assignee = null; + + @JsonProperty("jurisdiction") + @Valid + private List jurisdiction = null; + + @JsonProperty("offset") + private Integer offset = null; + + @JsonProperty("limit") + private Integer limit = null; + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/PlanSearchRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/PlanSearchRequest.java new file mode 100644 index 00000000000..23e4c7eb9bc --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/PlanSearchRequest.java @@ -0,0 +1,30 @@ +package org.egov.processor.web; + +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; + +/** + * PlanSearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanSearchRequest { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("PlanSearchCriteria") + @Valid + private PlanSearchCriteria planSearchCriteria = null; + + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/controllers/FileController.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/FileController.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/controllers/FileController.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/controllers/FileController.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Activity.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Activity.java similarity index 99% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Activity.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/Activity.java index fa9e1193e90..6c093ba63a2 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Activity.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Activity.java @@ -1,15 +1,17 @@ package org.egov.processor.web.models; import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +import jakarta.validation.constraints.Size; +import org.springframework.validation.annotation.Validated; 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; +import lombok.Data; +import lombok.Builder; /** * Activity diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Assumption.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Assumption.java new file mode 100644 index 00000000000..5f1d262fea7 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Assumption.java @@ -0,0 +1,58 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import java.math.BigDecimal; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.Digits; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * 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 = "The Assumption value must be greater than 0") + @DecimalMax(value = "9999999999.99", inclusive = true, message = "The assumption value must not exceed 10 digits in total, including up to 2 decimal places.") + @Digits(integer = 10, fraction = 2, message = "The Assumption value must have up to 10 digits and up to 2 decimal points") + private BigDecimal value = null; + + @JsonProperty("source") + @NotNull(message = "Source cannot be null. Please specify a valid source.") + private Source source = null; + + @JsonProperty("category") + @NotNull + @Size(min = 2, max = 64) + private String category = 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-generator/src/main/java/org/egov/processor/web/models/Condition.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Condition.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/Condition.java index 51d3511c068..c63749d5bab 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Condition.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Condition.java @@ -3,11 +3,11 @@ import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; +import org.springframework.validation.annotation.Validated; import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; +import lombok.Data; +import lombok.Builder; /** * Condition diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/File.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/File.java similarity index 81% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/File.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/File.java index fe6b6c1abab..25a62e8ac83 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/File.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/File.java @@ -1,17 +1,20 @@ package org.egov.processor.web.models; -import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; 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 org.apache.kafka.common.protocol.types.Field; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; +import lombok.Data; +import lombok.Builder; + +import java.util.Arrays; /** * File @@ -30,7 +33,7 @@ public class File { @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") + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Filestore Id must not contain only special characters") private String filestoreId = null; @JsonProperty("inputFileType") @@ -40,7 +43,7 @@ public class File { @JsonProperty("templateIdentifier") @NotNull @Size(min = 2, max = 128) - @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Name must contain alphanumeric characters and may include some special characters") + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Name must not contain only special characters") private String templateIdentifier = null; @JsonProperty("active") @@ -71,12 +74,10 @@ public String toString() { @JsonCreator public static InputFileTypeEnum fromValue(String text) { - for (InputFileTypeEnum b : InputFileTypeEnum.values()) { - if (String.valueOf(b.value).equals(text)) { - return b; - } - } - return null; + return Arrays.stream(InputFileTypeEnum.values()) + .filter(b -> String.valueOf(b.value).equals(text)) + .findFirst() + .orElse(null); // Return null if no matching enum value is found } } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Locale.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Locale.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Locale.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/Locale.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/LocaleResponse.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/LocaleResponse.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/LocaleResponse.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/LocaleResponse.java diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/MetricDetail.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/MetricDetail.java new file mode 100644 index 00000000000..b21b1a62560 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/MetricDetail.java @@ -0,0 +1,75 @@ +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.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.Digits; +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; + +import java.math.BigDecimal; +import java.util.Arrays; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class MetricDetail { + + @JsonProperty("value") + @NotNull + @DecimalMin(value = "0.01", inclusive = true, message = "Metric value must be greater than 0") + @DecimalMax(value = "999.99", inclusive = true, message = "Metric value must be less than 1000") + @Digits(integer = 3, fraction = 2, message = "Metric value must have up to 3 digits and up to 2 decimal points") + private BigDecimal metricValue = null; + + @JsonProperty("comparator") + @NotNull + private MetricComparatorEnum metricComparator = null; + + @JsonProperty("unit") + @NotNull + @Size(min = 1, max = 128) + private String metricUnit = null; + + public enum MetricComparatorEnum { + GREATER_THAN(">"), + + LESS_THAN("<"), + + GREATER_THAN_OR_EQUAL_TO(">="), + + LESS_THAN_OR_EQUAL_TO("<="), + + EQUAL("="); + + private final String symbol; + + MetricComparatorEnum(String symbol) { + this.symbol = symbol; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(symbol); + } + + @JsonCreator + public static MetricComparatorEnum fromValue(String text) { + return Arrays.stream(MetricComparatorEnum.values()) + .filter(b -> String.valueOf(b.symbol).equals(text)) + .findFirst() + .orElse(null); // Return null if no matching enum value is found + } + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Operation.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Operation.java similarity index 70% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Operation.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/Operation.java index 25b5b189fa0..5194da66b18 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Operation.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Operation.java @@ -1,17 +1,19 @@ package org.egov.processor.web.models; -import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; -import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; +import lombok.Data; +import lombok.Builder; + +import java.util.Arrays; /** * Operation @@ -46,6 +48,22 @@ public class Operation { @Size(min = 1, max = 64) private String output = null; + @JsonProperty("showOnEstimationDashboard") + @NotNull + private Boolean showOnEstimationDashboard = true; + + @JsonProperty("source") + @NotNull(message = "Source cannot be null. Please specify a valid source.") + private Source source = null; + + @JsonProperty("category") + @NotNull + @Size(min = 2, max = 64) + private String category = null; + + @JsonProperty("executionOrder") + private Integer executionOrder = null; + @JsonProperty("active") @NotNull private Boolean active = true; @@ -80,12 +98,10 @@ public String toString() { @JsonCreator public static OperatorEnum fromValue(String text) { - for (OperatorEnum b : OperatorEnum.values()) { - if (String.valueOf(b.value).equals(text)) { - return b; - } - } - return null; + return Arrays.stream(OperatorEnum.values()) + .filter(b -> String.valueOf(b.value).equals(text)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unexpected value '" + text + "'")); } } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Plan.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Plan.java similarity index 63% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Plan.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/Plan.java index a9d4f3139b5..8b2f1803f57 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Plan.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Plan.java @@ -1,17 +1,20 @@ package org.egov.processor.web.models; +import com.fasterxml.jackson.annotation.JsonIgnore; 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.egov.common.contract.models.Workflow; import org.springframework.validation.annotation.Validated; +import java.util.List; + /** * Plan */ @@ -34,30 +37,51 @@ public class Plan { @Size(min = 1, max = 64) private String locality = null; - @JsonProperty("executionPlanId") + @JsonProperty("campaignId") @Size(max = 64) - private String executionPlanId = null; + private String campaignId = null; @JsonProperty("planConfigurationId") @Size(max = 64) private String planConfigurationId = null; + @JsonProperty("status") + @Size(max = 64) + private String status = null; + + @JsonProperty("assignee") + @Size(max = 64) + private String assignee = null; + @JsonProperty("additionalDetails") private Object additionalDetails = null; @JsonProperty("activities") @Valid - private List activities = null; + private List activities; @JsonProperty("resources") @Valid - private List resources = null; + private List resources; @JsonProperty("targets") @Valid - private List targets = null; + private List targets; @JsonProperty("auditDetails") private AuditDetails auditDetails = null; + @JsonIgnore + private String boundaryAncestralPath = null; + + @JsonIgnore + private boolean isRequestFromResourceEstimationConsumer; + + @JsonIgnore + private List assigneeJurisdiction; + + @JsonProperty("workflow") + @Valid + private Workflow workflow; + } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfiguration.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfiguration.java similarity index 68% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfiguration.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfiguration.java index e02d7e49b70..218dbaecbea 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfiguration.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfiguration.java @@ -1,14 +1,15 @@ 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.egov.common.contract.models.Workflow; import org.springframework.validation.annotation.Validated; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; @@ -36,54 +37,43 @@ public class PlanConfiguration { @JsonProperty("name") @NotNull - @Size(min = 2, max = 128) - @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Name must not contain only special characters") + @Size(min = 3, max = 128) private String name = null; - @JsonProperty("executionPlanId") + @JsonProperty("campaignId") @NotNull @Size(min = 2, max = 64) - @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Execution Plan Id must not contain only special characters") - private String executionPlanId = null; + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Campaign Id must not contain only special characters") + private String campaignId = null; @JsonProperty("status") - @NotNull - private StatusEnum status = null; + private String 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 - } + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("workflow") + @Valid + private Workflow workflow; + } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfigurationRequest.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationRequest.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfigurationRequest.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationResponse.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfigurationResponse.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationResponse.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfigurationResponse.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchCriteria.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchCriteria.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchCriteria.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchCriteria.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchRequest.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchRequest.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchRequest.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanRequest.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanRequest.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/PlanRequest.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Resource.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Resource.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Resource.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/Resource.java index 5fea454bd5d..693ba12ef32 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Resource.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Resource.java @@ -1,14 +1,14 @@ package org.egov.processor.web.models; import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; -import java.math.BigDecimal; +import org.springframework.validation.annotation.Validated; import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; +import lombok.Data; +import lombok.Builder; /** * Resource diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/ResourceMapping.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/ResourceMapping.java similarity index 99% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/ResourceMapping.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/ResourceMapping.java index c53868d1033..ee9e1869c0c 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/ResourceMapping.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/ResourceMapping.java @@ -1,15 +1,16 @@ 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 org.springframework.validation.annotation.Validated; import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; +import lombok.Data; +import lombok.Builder; /** * ResourceMapping diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Source.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Source.java new file mode 100644 index 00000000000..3d726b35f9f --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Source.java @@ -0,0 +1,5 @@ +package org.egov.processor.web.models; + +public enum Source { + MDMS, CUSTOM, VEHICLE; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Target.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Target.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Target.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/Target.java index 8d7298939f6..6855fccb123 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Target.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/Target.java @@ -3,11 +3,11 @@ import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.Valid; import jakarta.validation.constraints.Size; +import org.springframework.validation.annotation.Validated; import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; +import lombok.Data; +import lombok.Builder; /** * Target diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/BoundarySearchResponse.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/boundary/BoundarySearchResponse.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/BoundarySearchResponse.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/boundary/BoundarySearchResponse.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/EnrichedBoundary.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/boundary/EnrichedBoundary.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/EnrichedBoundary.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/boundary/EnrichedBoundary.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/HierarchyRelation.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/boundary/HierarchyRelation.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/HierarchyRelation.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/boundary/HierarchyRelation.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/AdditionalDetails.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/AdditionalDetails.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/AdditionalDetails.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/AdditionalDetails.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Boundary.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/Boundary.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Boundary.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/Boundary.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java similarity index 94% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java index 352b29b693b..51c390a2af5 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java @@ -1,12 +1,6 @@ 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; @@ -14,6 +8,10 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import java.util.List; @Validated @Data @@ -37,7 +35,13 @@ public class Campaign { @JsonProperty("action") @Size(min = 1, max = 64) private String action; - + + @JsonProperty("isActive") + private boolean isActive; + + @JsonProperty("parentId") + private String parentId; + @JsonProperty("campaignNumber") @Valid private String campaignNumber; diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignCondition.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignCondition.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignCondition.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignCondition.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignDetails.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignDetails.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignDetails.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignDetails.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignRequest.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignRequest.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignRequest.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResources.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResources.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResources.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResources.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResponse.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResponse.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResponse.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResponse.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignSearchRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignSearchRequest.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignSearchRequest.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CampaignSearchRequest.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleConfigureDate.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CycleConfigureDate.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleConfigureDate.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CycleConfigureDate.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleData.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CycleData.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleData.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/CycleData.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/DeliveryRule.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/DeliveryRule.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/DeliveryRule.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/DeliveryRule.java diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/MicroplanDetails.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/MicroplanDetails.java new file mode 100644 index 00000000000..4bbb44b118b --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/MicroplanDetails.java @@ -0,0 +1,32 @@ +package org.egov.processor.web.models.campaignManager; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Validated +public class MicroplanDetails { + + @JsonProperty("tenantId") + @NotNull + private String tenantId; + + @JsonProperty("campaignId") + @NotNull + private String campaignId; + + @JsonProperty("planConfigurationId") + @NotNull + private String planConfigurationId; + + @JsonProperty("resourceFilestoreId") + private String resourceFilestoreId; +} \ No newline at end of file diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/MicroplanDetailsRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/MicroplanDetailsRequest.java new file mode 100644 index 00000000000..4789ef42573 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/MicroplanDetailsRequest.java @@ -0,0 +1,26 @@ +package org.egov.processor.web.models.campaignManager; + +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; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class MicroplanDetailsRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("MicroplanDetails") + @Valid + private MicroplanDetails microplanDetails = null; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Product.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/Product.java similarity index 100% rename from health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Product.java rename to health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/Product.java diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/ResourceDetails.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/ResourceDetails.java new file mode 100644 index 00000000000..b35c0343469 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/ResourceDetails.java @@ -0,0 +1,48 @@ +package org.egov.processor.web.models.campaignManager; + +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; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ResourceDetails { + + @JsonProperty("type") + @NotNull + @Size(min = 1, max = 64) + private String type; + + @JsonProperty("hierarchyType") + @NotNull + @Size(min = 1, max = 64) + private String hierarchyType; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId; + + @JsonProperty("fileStoreId") + @NotNull + private String fileStoreId; + + @JsonProperty("action") + @Size(min = 1, max = 64) + private String action; + + @JsonProperty("campaignId") + private String campaignId; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/ResourceDetailsRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/ResourceDetailsRequest.java new file mode 100644 index 00000000000..265d4fcdc0e --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/campaignManager/ResourceDetailsRequest.java @@ -0,0 +1,30 @@ +package org.egov.processor.web.models.campaignManager; + +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; + +/** + * CensusRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ResourceDetailsRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("ResourceDetails") + @Valid + private ResourceDetails resourceDetails = null; + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/AdditionalField.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/AdditionalField.java new file mode 100644 index 00000000000..972ca77bb4b --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/AdditionalField.java @@ -0,0 +1,48 @@ +package org.egov.processor.web.models.census; + +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.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; + +/** + * AdditionalField + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AdditionalField { + + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("key") + @Valid + @NotNull + private String key = null; + + @JsonProperty("value") + @Valid + @NotNull + private BigDecimal value = null; + + @JsonProperty("showOnUi") + private Boolean showOnUi = Boolean.TRUE; + + @JsonProperty("editable") + private Boolean editable = Boolean.TRUE; + + @JsonProperty("order") + private Integer order = null; +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/Census.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/Census.java new file mode 100644 index 00000000000..f895f6c75f1 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/Census.java @@ -0,0 +1,138 @@ +package org.egov.processor.web.models.census; + + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +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.egov.common.contract.models.AuditDetails; +import org.egov.common.contract.models.Workflow; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; +import java.util.List; + + +/** + * Census + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Census { + + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("tenantId") + @NotNull + private String tenantId = null; + + @JsonProperty("hierarchyType") + @NotNull + private String hierarchyType = null; + + @JsonProperty("boundaryCode") + @NotNull + private String boundaryCode = null; + + @JsonProperty("assignee") + @Size(max = 64) + private String assignee = null; + + @JsonProperty("status") + @Size(max = 64) + private String status = null; + + @JsonProperty("type") + @NotNull + private TypeEnum type = null; + + @JsonProperty("totalPopulation") + @NotNull + private BigDecimal totalPopulation = null; + + @JsonProperty("populationByDemographics") + @Valid + private List populationByDemographics = null; + + @JsonProperty("effectiveFrom") + private Long effectiveFrom = null; + + @JsonProperty("effectiveTo") + private Long effectiveTo = null; + + @JsonProperty("source") + @NotNull + private String source = null; + + @JsonIgnore + private List boundaryAncestralPath = null; + + @JsonIgnore + private boolean partnerAssignmentValidationEnabled; + + @JsonProperty("facilityAssigned") + private Boolean facilityAssigned = null; + + @JsonProperty("workflow") + @Valid + private Workflow workflow; + + @JsonIgnore + private List assigneeJurisdiction; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("additionalFields") + @Valid + private List additionalFields = null; + + @JsonProperty("auditDetails") + private @Valid AuditDetails auditDetails; + + /** + * Gets or Sets type + */ + public enum TypeEnum { + PEOPLE("people"), + ANIMALS("animals"), + PLANTS("plants"), + OTHER("other"); + + private String value; + + TypeEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static TypeEnum fromValue(String text) { + for (TypeEnum b : TypeEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusRequest.java new file mode 100644 index 00000000000..08a9c3bdbce --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusRequest.java @@ -0,0 +1,31 @@ +package org.egov.processor.web.models.census; + +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; + +/** + * CensusRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Census") + @Valid + private Census census = null; + + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusResponse.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusResponse.java new file mode 100644 index 00000000000..7e6c0b77440 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusResponse.java @@ -0,0 +1,41 @@ +package org.egov.processor.web.models.census; + +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.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import java.util.List; +import java.util.Map; + +/** + * CensusResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Census") + @Valid + private List census = null; + + @JsonProperty("TotalCount") + @Valid + private Integer totalCount = null; + + @JsonProperty("StatusCount") + @Valid + private Map statusCount = null; + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusSearchCriteria.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusSearchCriteria.java new file mode 100644 index 00000000000..9ed59d11d63 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusSearchCriteria.java @@ -0,0 +1,71 @@ +package org.egov.processor.web.models.census; + + +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; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * CensusSearchCriteria + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusSearchCriteria { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("ids") + private Set ids = null; + + @JsonProperty("tenantId") + @Size(min = 1, max = 100) + private String tenantId = null; + + @JsonProperty("areaCodes") + private List areaCodes = null; + + @JsonProperty("status") + private String status = null; + + @JsonProperty("assignee") + private String assignee = null; + + @JsonProperty("source") + private String source = null; + + @JsonProperty("facilityAssigned") + private Boolean facilityAssigned = null; + + @JsonProperty("jurisdiction") + private List jurisdiction = null; + + @JsonProperty("effectiveTo") + private Long effectiveTo = null; + + @JsonProperty("limit") + private Integer limit = null; + + @JsonProperty("offset") + private Integer offset = null; + + public CensusSearchCriteria addAreaCodesItem(String areaCodesItem) { + if (this.areaCodes == null) { + this.areaCodes = new ArrayList<>(); + } + this.areaCodes.add(areaCodesItem); + return this; + } + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusSearchRequest.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusSearchRequest.java new file mode 100644 index 00000000000..ef7439bc368 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/CensusSearchRequest.java @@ -0,0 +1,31 @@ +package org.egov.processor.web.models.census; + +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; + +/** + * CensusSearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CensusSearchRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("CensusSearchCriteria") + @Valid + private CensusSearchCriteria censusSearchCriteria = null; + + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/PopulationByDemographic.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/PopulationByDemographic.java new file mode 100644 index 00000000000..52ab230781b --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/census/PopulationByDemographic.java @@ -0,0 +1,69 @@ +package org.egov.processor.web.models.census; + + +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.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * PopulationByDemographic + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PopulationByDemographic { + + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("demographicVariable") + private DemographicVariableEnum demographicVariable = null; + + @JsonProperty("populationDistribution") + private Object populationDistribution = null; + + /** + * Gets or Sets demographicVariable + */ + public enum DemographicVariableEnum { + AGE("age"), + + GENDER("gender"), + + ETHNICITY("ethnicity"); + + private String value; + + DemographicVariableEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static DemographicVariableEnum fromValue(String text) { + for (DemographicVariableEnum b : DemographicVariableEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + +} diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/Mdms.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/Mdms.java new file mode 100644 index 00000000000..b591caf0929 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/Mdms.java @@ -0,0 +1,55 @@ +package org.egov.processor.web.models.mdmsV2; + +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.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/** + * Mdms + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Mdms { + + @JsonProperty("id") + @Size(min = 2, max = 64) + private String id; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 128) + private String tenantId = null; + + @JsonProperty("schemaCode") + @NotNull + @Size(min = 2, max = 128) + private String schemaCode = null; + + @JsonProperty("uniqueIdentifier") + @Size(min = 2, max = 128) + private String uniqueIdentifier = null; + + @JsonProperty("data") + @NotNull + private JsonNode data = null; + + @JsonProperty("isActive") + private Boolean isActive = true; + + @JsonProperty("auditDetails") + @Valid + private AuditDetails auditDetails = null; + +} \ No newline at end of file diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsCriteriaReqV2.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsCriteriaReqV2.java new file mode 100644 index 00000000000..65c7123d5ca --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsCriteriaReqV2.java @@ -0,0 +1,26 @@ +package org.egov.processor.web.models.mdmsV2; + +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; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class MdmsCriteriaReqV2 { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo; + + @JsonProperty("MdmsCriteria") + @Valid + private MdmsCriteriaV2 mdmsCriteriaV2; +} \ No newline at end of file diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsCriteriaV2.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsCriteriaV2.java new file mode 100644 index 00000000000..c7832894ebc --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsCriteriaV2.java @@ -0,0 +1,62 @@ +package org.egov.processor.web.models.mdmsV2; + +import com.fasterxml.jackson.annotation.JsonIgnore; +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; +import javax.validation.constraints.Size; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Data +@Validated +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class MdmsCriteriaV2 { + + @JsonProperty("tenantId") + @Size(min = 1, max = 100) + @NotNull + private String tenantId; + + @JsonProperty("ids") + private Set ids; + + @JsonProperty("uniqueIdentifier") + @Size(min = 1, max = 64) + private String uniqueIdentifier; + + @JsonProperty("uniqueIdentifiers") + private List uniqueIdentifiers; + + @JsonProperty("schemaCode") + private String schemaCode; + + @JsonProperty("filters") + private Map filterMap; + + @JsonProperty("isActive") + private Boolean isActive; + + @JsonIgnore + private Map schemaCodeFilterMap; + + @JsonIgnore + private Set uniqueIdentifiersForRefVerification; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} \ No newline at end of file diff --git a/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsResponseV2.java b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsResponseV2.java new file mode 100644 index 00000000000..2b570e66f08 --- /dev/null +++ b/health-services/resource-generator/src/main/java/org/egov/processor/web/models/mdmsV2/MdmsResponseV2.java @@ -0,0 +1,28 @@ +package org.egov.processor.web.models.mdmsV2; + +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 java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) + +public class MdmsResponseV2 { + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("mdms") + @Valid + private List mdms = null; +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/resources/application.properties b/health-services/resource-generator/src/main/resources/application.properties similarity index 68% rename from health-services/resource-estimation-service/src/main/resources/application.properties rename to health-services/resource-generator/src/main/resources/application.properties index 7cdfe225f6d..45e36a74e5c 100644 --- a/health-services/resource-estimation-service/src/main/resources/application.properties +++ b/health-services/resource-generator/src/main/resources/application.properties @@ -1,5 +1,5 @@ -server.contextPath=/resource-estimation-service -server.servlet.context-path=/resource-estimation-service +server.contextPath=/resource-generator +server.servlet.context-path=/resource-generator server.port=8083 app.timezone=UTC @@ -47,6 +47,7 @@ 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 +egov.mdms.search.v2.endpoint=/mdms-v2/v2/_search #plan config egov.plan.config.host=https://unified-dev.digit.org @@ -65,19 +66,43 @@ plan.config.consumer.kafka.update.topic=plan-config-update-topic #Plan Create egov.plan.create.endpoint=/plan-service/plan/_create +egov.plan.search.endpoint=/plan-service/plan/_search #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.data.create.endpoint=/project-factory/v1/data/_create +egov.project.factory.fetch.from.microplan.endpoint=/project-factory/v1/project-type/fetch-from-microplan egov.project.factory.host=https://unified-dev.digit.org #egov.project.factory.host=http://localhost:8090 +integrate.with.admin.console=false + +#Kafka topics for creating or updating records in dependent microservices resource.microplan.create.topic=resource-microplan-create-topic resource.update.plan.config.consumer.topic=resource-plan-config-update-topic -integrate.with.admin.console=true +resource.census.create.topic=resource-census-create-topic 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} 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 +egov.locale.search.endpoint=/localization/messages/v1/_search?module={module}&locale={locale}&tenantId={tenantId} + +#trigger statuses +plan.config.trigger.plan.estimates.status=RESOURCE_ESTIMATION_IN_PROGRESS +plan.config.trigger.census.records.status=EXECUTION_TO_BE_DONE +plan.config.trigger.plan.facility.mappings.status=EXECUTION_TO_BE_DONE +plan.config.update.plan.estimates.into.output.file.status=RESOURCE_ESTIMATIONS_APPROVED + +# Pagination config +resource.default.offset=0 +resource.default.limit=10 + +# Census +egov.census.host=https://unified-dev.digit.org +egov.census.search.endpoint=/census-service/_search + +census.additional.field.override.keys=HCM_ADMIN_CONSOLE_BOUNDARY_CODE +census.additional.field.prefix.append.keys=HCM_ADMIN_CONSOLE_TOTAL_POPULATION,HCM_ADMIN_CONSOLE_TARGET_POPULATION,HCM_ADMIN_CONSOLE_TARGET_POPULATION_AGE_3TO11,HCM_ADMIN_CONSOLE_TARGET_POPULATION_AGE_12TO59 +census.additional.field.show.on.ui.false.keys=HCM_ADMIN_CONSOLE_TARGET_LAT_OPT,HCM_ADMIN_CONSOLE_TARGET_LONG_OPT \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/resources/db/Dockerfile b/health-services/resource-generator/src/main/resources/db/Dockerfile similarity index 83% rename from health-services/resource-estimation-service/src/main/resources/db/Dockerfile rename to health-services/resource-generator/src/main/resources/db/Dockerfile index 60fc07ce69f..f5241a8f861 100644 --- a/health-services/resource-estimation-service/src/main/resources/db/Dockerfile +++ b/health-services/resource-generator/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 diff --git a/health-services/resource-generator/src/main/resources/db/migrate.sh b/health-services/resource-generator/src/main/resources/db/migrate.sh new file mode 100644 index 00000000000..c58d6f91e3f --- /dev/null +++ b/health-services/resource-generator/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 migrate \ No newline at end of file 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. diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index d204ba58903..5cb0c17da56 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -45,12 +45,12 @@ org.egov.common health-services-common - 1.0.18-SNAPSHOT + 1.0.20-dev-SNAPSHOT org.egov.common health-services-models - 1.0.20-SNAPSHOT + 1.0.23-dev-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 813246f8a2b..d05bca6fdd1 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 @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.stock.StockReconciliation; import org.springframework.jdbc.core.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 e413a3052ac..ea57dbad66d 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 @@ -5,7 +5,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.models.AuditDetails; import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.stock.ReferenceIdType; import org.egov.common.models.stock.SenderReceiverType; 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 67c3cc9b3b6..c30480b1371 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.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.stock.StockReconciliation; import org.egov.common.models.stock.StockReconciliationBulkRequest; import org.egov.common.models.stock.StockReconciliationRequest; @@ -180,26 +181,27 @@ public List delete(StockReconciliationBulkRequest request, return validEntities; } - public List search(StockReconciliationSearchRequest request, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { + public SearchResponse search(StockReconciliationSearchRequest request, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { log.info("starting search method for stock reconciliation"); String idFieldName = getIdFieldName(request.getStockReconciliation()); if (isSearchByIdOnly(request.getStockReconciliation(), idFieldName)) { List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections .singletonList(request.getStockReconciliation())), request.getStockReconciliation()); - return stockRepository.findById(ids, includeDeleted, idFieldName).stream() + List stockReconciliations = stockRepository.findById(ids, includeDeleted, idFieldName).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); + return SearchResponse.builder().response(stockReconciliations).build(); } log.info("completed search method for stock reconciliation"); - return stockRepository.find(request.getStockReconciliation(), + return stockRepository.findWithCount(request.getStockReconciliation(), limit, offset, tenantId, lastChangedSince, includeDeleted); } } 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 c5d2769ca6e..8cbccb66b27 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 @@ -10,6 +10,7 @@ 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; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockBulkRequest; import org.egov.common.models.stock.StockRequest; @@ -175,27 +176,28 @@ public List delete(StockBulkRequest request, boolean isBulk) { return validEntities; } - public List search(StockSearchRequest stockSearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { + public SearchResponse search(StockSearchRequest stockSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { log.info("starting search method for stock"); String idFieldName = getIdFieldName(stockSearchRequest.getStock()); if (isSearchByIdOnly(stockSearchRequest.getStock(), idFieldName)) { List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections .singletonList(stockSearchRequest.getStock())), stockSearchRequest.getStock()); - return stockRepository.findById(ids, includeDeleted, idFieldName).stream() + List stocks = stockRepository.findById(ids, includeDeleted, idFieldName).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); + return SearchResponse.builder().response(stocks).build(); } log.info("completed search method for stock"); - return stockRepository.find(stockSearchRequest.getStock(), + return stockRepository.findWithCount(stockSearchRequest.getStock(), limit, offset, tenantId, lastChangedSince, includeDeleted); } } 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 091b6020a7c..9675b3f6172 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 @@ -6,8 +6,8 @@ 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.contract.user.UserSearchRequest; import org.egov.common.ds.Tuple; import org.egov.common.models.Error; import org.egov.common.models.stock.SenderReceiverType; 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 913213dd191..7033f50a14a 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 @@ -8,6 +8,7 @@ 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.stock.Stock; import org.egov.common.models.stock.StockBulkRequest; @@ -80,7 +81,7 @@ public ResponseEntity stockV1SearchPost( @ApiParam(value = "Capture details of Stock Transfer.", required = true) @Valid @RequestBody StockSearchRequest stockSearchRequest ) throws Exception { - List stock = stockService.search( + SearchResponse searchResponse = stockService.search( stockSearchRequest, urlParams.getLimit(), urlParams.getOffset(), @@ -89,7 +90,7 @@ public ResponseEntity stockV1SearchPost( urlParams.getIncludeDeleted() ); StockBulkResponse response = StockBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(stockSearchRequest.getRequestInfo(), true)).stock(stock).build(); + .createResponseInfo(stockSearchRequest.getRequestInfo(), true)).stock(searchResponse.getResponse()).totalCount(searchResponse.getTotalCount()).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 e612c3b692f..41fc33437e9 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 @@ -7,6 +7,7 @@ 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.stock.StockReconciliation; import org.egov.common.models.stock.StockReconciliationBulkRequest; @@ -77,7 +78,7 @@ public ResponseEntity stockReconciliationV1Sear @ApiParam(value = "Capture details of Stock Reconciliation.", required = true) @Valid @RequestBody StockReconciliationSearchRequest stockReconciliationSearchRequest ) throws Exception { - List stock = stockReconciliationService.search( + SearchResponse searchResponse = stockReconciliationService.search( stockReconciliationSearchRequest, urlParams.getLimit(), urlParams.getOffset(), @@ -86,7 +87,10 @@ public ResponseEntity stockReconciliationV1Sear urlParams.getIncludeDeleted() ); StockReconciliationBulkResponse response = StockReconciliationBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(stockReconciliationSearchRequest.getRequestInfo(), true)).stockReconciliation(stock).build(); + .createResponseInfo(stockReconciliationSearchRequest.getRequestInfo(), true)) + .stockReconciliation(searchResponse.getResponse()) + .totalCount(searchResponse.getTotalCount()) + .build(); return ResponseEntity.status(HttpStatus.OK).body(response); }