diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 00000000000..b45386a0866 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,15 @@ +# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json +language: "en-US" +early_access: false +reviews: + profile: "assertive" + request_changes_workflow: true + high_level_summary: true + poem: true + review_status: true + collapse_walkthrough: false + auto_review: + enabled: true + drafts: false +chat: + auto_reply: true 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 new file mode 100644 index 00000000000..1a0c526d1bf --- /dev/null +++ b/.github/workflows/buildWorkbenchUI.yml @@ -0,0 +1,64 @@ +name: Digit Admin Console Build workflow +on: + push: + branches: + - campaign + paths: + - 'micro-ui/web/micro-ui-internals/**' + pull_request: + branches: + - campaign + workflow_dispatch: +jobs: + docker_image-build: + outputs: + run_job_digit_ui: ${{ steps.check_files.outputs.run_job_digit_ui }} + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + fetch-depth: 2 + - name: Setup Docker + uses: docker/setup-buildx-action@v1 + - name: check modified files + id: check_files + run: | + echo "=============== list modified files ===============" + git diff --name-only HEAD^ HEAD + + echo "========== check paths of modified files ==========" + git diff --name-only HEAD^ HEAD > files.txt + run_job_digit_ui=false + while IFS= read -r file + do + if [[ $file == micro-ui/* ]]; then + echo "This modified file is under the 'digit_ui' folder." + run_job_digit_ui=true + fi + done < files.txt + + # Set the output based on whether the job should run + echo "::set-output name=run_job_digit_ui::$run_job_digit_ui" + echo "ACTION_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV + echo "COMMIT_ID=${GITHUB_SHA: -8}" >> $GITHUB_ENV # Extract last 8 characters of SHA + echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV + + + + + - name: Login to egovio docker Container Registry + env: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + run: | + # Authenticate with Docker Hub + echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin + + - name: Build and Push Docker image for digit-ui + if: ${{ steps.check_files.outputs.run_job_digit_ui == 'true' }} + run: | + docker build -t workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} -f web/workbench/Dockerfile . + docker tag workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} egovio/workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} + docker push egovio/workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} + working-directory: micro-ui diff --git a/.github/workflows/codacy.yml b/.github/workflows/codacy.yml new file mode 100644 index 00000000000..37a5171543e --- /dev/null +++ b/.github/workflows/codacy.yml @@ -0,0 +1,61 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +# This workflow checks out code, performs a Codacy security scan +# and integrates the results with the +# GitHub Advanced Security code scanning feature. For more information on +# the Codacy security scan action usage and parameters, see +# https://github.com/codacy/codacy-analysis-cli-action. +# For more information on Codacy Analysis CLI in general, see +# https://github.com/codacy/codacy-analysis-cli. + +name: Codacy Security Scan + +on: + push: + branches: [ "master", "master|hlm-[0-9]+.*", "dev" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "master", "dev" ] + schedule: + - cron: '30 13 * * 1' + +permissions: + contents: read + +jobs: + codacy-security-scan: + permissions: + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/upload-sarif to upload SARIF results + actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status + name: Codacy Security Scan + runs-on: ubuntu-latest + steps: + # Checkout the repository to the GitHub Actions runner + - name: Checkout code + uses: actions/checkout@v3 + + # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis + - name: Run Codacy Analysis CLI + uses: codacy/codacy-analysis-cli-action@d840f886c4bd4edc059706d09c6a1586111c540b + with: + # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository + # You can also omit the token and run the tools that support default configurations + project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} + verbose: true + output: results.sarif + format: sarif + # Adjust severity of non-security issues + gh-code-scanning-compat: true + # Force 0 exit code to allow SARIF file generation + # This will handover control about PR rejection to the GitHub side + max-allowed-issues: 2147483647 + + # Upload the SARIF file generated in the previous step + - name: Upload SARIF results file + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: results.sarif diff --git a/.github/workflows/publishAllPackages.yml b/.github/workflows/publishAllPackages.yml new file mode 100644 index 00000000000..6bb4b51d612 --- /dev/null +++ b/.github/workflows/publishAllPackages.yml @@ -0,0 +1,25 @@ +name: Node.js Publish UI Packages + +on: + push: + branches: [ 'develop','campaign' ] + paths: + - 'micro-ui/web/micro-ui-internals/**' + + pull_request: + branches: + - 'dev-hcm' + # Push events to branches matching refs/heads/mona/octocat + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 14 + registry-url: https://registry.npmjs.org/ + - run: cd micro-ui/web/micro-ui-internals/ && bash ./publish-develop.sh + env: + NODE_AUTH_TOKEN: ${{secrets.npm_token}} diff --git a/.github/workflows/publishAllPackagesRelease.yml b/.github/workflows/publishAllPackagesRelease.yml new file mode 100644 index 00000000000..ff9b6a3a93f --- /dev/null +++ b/.github/workflows/publishAllPackagesRelease.yml @@ -0,0 +1,20 @@ +name: Node.js Publish UI Packages + +on: + push: + branches: [ 'master' ] + paths: + - 'micro-ui/web/micro-ui-internals/**' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 14 + registry-url: https://registry.npmjs.org/ + - run: cd micro-ui/web/micro-ui-internals/ && bash ./publish.sh + env: + NODE_AUTH_TOKEN: ${{secrets.npm_token}} diff --git a/.github/workflows/publishProjectFactory.yml b/.github/workflows/publishProjectFactory.yml new file mode 100644 index 00000000000..19fde98c7ab --- /dev/null +++ b/.github/workflows/publishProjectFactory.yml @@ -0,0 +1,77 @@ +name: project factory service docker Image CI + +on: + push: + branches: [ "campaign" ] + paths: + - 'utilities/project-factory/**' + pull_request: + branches: [ "campaign" ] + +jobs: + + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # Fetch all history for tags and branches + + - name: Set up environment variables + id: env + run: | + echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV + echo "ACTION_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV + echo "COMMIT_ID=${GITHUB_SHA: -8}" >> $GITHUB_ENV # Extract last 8 characters of SHA + + - name: Build the service Docker image + id: docker_build + working-directory: ./utilities/project-factory + run: | + IMAGE_TAG=egovio/project-factory:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} + docker build . \ + --file Dockerfile \ + --tag $IMAGE_TAG + echo "::set-output name=image_name::$IMAGE_TAG" + + + - name: Build the db migration Docker image + id: docker_db_build + working-directory: ./utilities/project-factory/migration + run: | + IMAGE_TAG=egovio/project-factory-db:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} + docker build . \ + --file Dockerfile \ + --tag $IMAGE_TAG + echo "::set-output name=db_image_name::$IMAGE_TAG" + + + - name: Login to Docker Hub and Push Docker Image + working-directory: ./utilities/project-factory + env: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + IMAGE_NAME: ${{ steps.docker_build.outputs.image_name }} + run: | + # Authenticate with Docker Hub + echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin + + # Push the image to Docker Hub + docker push $IMAGE_NAME + echo "Docker image pushed: $IMAGE_NAME" + + - name: Login to Docker Hub and Push DB Migration Docker Image + working-directory: ./utilities/project-factory/migration + env: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + DB_IMAGE_NAME: ${{ steps.docker_db_build.outputs.db_image_name }} + run: | + # Authenticate with Docker Hub + echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin + + # Push the image to Docker Hub + docker push $DB_IMAGE_NAME + echo "Docker image pushed: $DB_IMAGE_NAME" diff --git a/.gitignore b/.gitignore index 423e1befca8..58c10f6dafe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,88 @@ .DS_Store -frontend/micro-ui-internals/node_modules/* .idea index.lock /health-services/stock/stock.iml +# Ignore target directories +**/target/ + +# Ignore IDE-specific files +*.iml +*.classpath +*.project +*.settings/ + +# Ignore gitignore files +**/.gitignore + +# Ignore compiled binaries and libraries +*.jar +*.war +*.ear +bin/ + +# Ignore system-specific files +.DS_Store +Thumbs.db +# Ignore target directories +**/target/ + +# Ignore IDE-specific files +*.iml +*.classpath +*.project +*.settings/ + +# Ignore gitignore files +**/.gitignore + +# Ignore compiled binaries and libraries +*.jar +*.war +*.ear + +# Ignore system-specific files +.DS_Store +Thumbs.db +# Ignore target directories +**/target/ + +# Ignore IDE-specific files +*.iml +*.classpath +*.project +*.settings/ + +# Ignore gitignore files +**/.gitignore + +# Ignore compiled binaries and libraries +*.jar +*.war +*.ear + +# Ignore system-specific files +.DS_Store +Thumbs.db +# Ignore target directories +**/target/ + +# Ignore IDE-specific files +*.iml +*.classpath +*.project +*.settings/ + +# Ignore gitignore files +**/.gitignore + +# Ignore compiled binaries and libraries +*.jar +*.war +*.ear + +# Ignore system-specific files +.DS_Store +Thumbs.db + +utilities/project-factory/node_modules/* +frontend/micro-ui/web/micro-ui-internals/node_modules/* \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json 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 b28b04f6431..e5b57cd157d 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,3 +1 @@ - - - +* @kavi-egov @sathishp-eGov \ No newline at end of file diff --git a/build/17/maven/Dockerfile b/build/17/maven/Dockerfile new file mode 100644 index 00000000000..0816437a705 --- /dev/null +++ b/build/17/maven/Dockerfile @@ -0,0 +1,34 @@ + +FROM egovio/amazoncorretto:17-alpine3.19 AS build +# FROM egovio/alpine-maven-builder-jdk-8:1-master-NA-6036091e AS build +#FROM ghcr.io/egovernments/alpine-maven-builder-jdk-8:1-master-na-6036091e AS build +ARG WORK_DIR +WORKDIR /app + +# Install Maven +RUN apk add --no-cache maven + +# copy the project files +COPY ${WORK_DIR}/pom.xml ./pom.xml +COPY build/maven/start.sh ./start.sh + +# not useful for stateless builds +# RUN mvn -B dependency:go-offline + +COPY ${WORK_DIR}/src ./src +RUN mvn -B -f /app/pom.xml package + + +# Create runtime image +#FROM egovio/8-openjdk-alpine +#FROM ghcr.io/egovernments/8-openjdk-alpine:latest +FROM egovio/amazoncorretto:17-alpine3.19 + + +WORKDIR /opt/egov + +COPY --from=build /app/target/*.jar /app/start.sh /opt/egov/ + +RUN chmod +x /opt/egov/start.sh + +CMD ["/opt/egov/start.sh"] diff --git a/build/build-config.yml b/build/build-config.yml index 4ab442bf983..2002805a366 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -36,6 +36,20 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "health-services/project/src/main/resources/db" image-name: "project-db" + - name: "builds/health-campaign-services/health-services/health-project" + build: + - work-dir: "health-services/project" + image-name: "health-project" + dockerfile: "build/maven/Dockerfile" + - work-dir: "health-services/project/src/main/resources/db" + image-name: "health-project-db" + - name: "builds/health-campaign-services/health-services/referralmanagement" + build: + - work-dir: "health-services/referralmanagement" + image-name: "referralmanagement" + dockerfile: "build/maven/Dockerfile" + - work-dir: "health-services/referralmanagement/src/main/resources/db" + image-name: "referralmanagement-db" - name: "builds/health-campaign-services/health-services/household" build: - work-dir: "health-services/household" @@ -43,6 +57,34 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "health-services/household/src/main/resources/db" image-name: "household-db" + - name: "builds/health-campaign-services/health-services/household-java-17" + build: + - work-dir: "health-services/household" + image-name: "household" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "health-services/household/src/main/resources/db" + image-name: "household-db" + - name: "builds/health-campaign-services/health-services/health-project-java-17" + build: + - work-dir: "health-services/project" + image-name: "health-project" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "health-services/project/src/main/resources/db" + image-name: "health-project-db" + - name: "builds/health-campaign-services/health-services/project-java-17" + build: + - work-dir: "health-services/project" + image-name: "project" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "health-services/project/src/main/resources/db" + image-name: "project-db" + - name: "builds/health-campaign-services/health-services/referralmanagement-java-17" + build: + - work-dir: "health-services/referralmanagement" + image-name: "referralmanagement" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "health-services/referralmanagement/src/main/resources/db" + image-name: "referralmanagement-db" - name: "builds/health-campaign-services/health-services/individual" build: - work-dir: "health-services/individual" @@ -50,13 +92,39 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "health-services/individual/src/main/resources/db" image-name: "individual-db" - - name: "builds/health-campaign-services/health-services/household" + - name: "builds/health-campaign-services/health-services/individual-java-17" build: - - work-dir: "health-services/household" - image-name: "household" + - work-dir: "health-services/individual" + image-name: "individual" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "health-services/individual/src/main/resources/db" + image-name: "individual-db" + - name: "builds/health-campaign-services/health-services/health-individual" + build: + - work-dir: "health-services/individual" + image-name: "health-individual" + dockerfile: "build/maven/Dockerfile" + - work-dir: "health-services/individual/src/main/resources/db" + image-name: "health-individual-db" + - name: "builds/health-campaign-services/health-services/health-individual-java-17" + build: + - work-dir: "health-services/individual" + image-name: "health-individual" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "health-services/individual/src/main/resources/db" + image-name: "health-individual-db" + - name: "builds/health-campaign-services/health-services/health-attendance" + build: + - work-dir: "health-services/attendance" + image-name: "health-attendance" + dockerfile: "build/maven/Dockerfile" + - work-dir: "health-services/attendance/src/main/resources/db" + image-name: "health-attendance-db" + - name: "builds/health-campaign-services/core-services/error-handler" + build: + - work-dir: "core-services/error-handler" + image-name: "error-handler" dockerfile: "build/maven/Dockerfile" - - work-dir: "health-services/household/src/main/resources/db" - image-name: "household-db" - name: "builds/health-campaign-services/core-services/dashboard-analytics" build: - work-dir: "core-services/dashboard-analytics" @@ -69,6 +137,13 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "health-services/stock/src/main/resources/db" image-name: "stock-db" + - name: "builds/health-campaign-services/health-services/stock-java-17" + build: + - work-dir: "health-services/stock" + image-name: "stock" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "health-services/stock/src/main/resources/db" + image-name: "stock-db" - name: "builds/health-campaign-services/core-services/egov-survey-services" build: - work-dir: "core-services/egov-survey-services" @@ -83,11 +158,23 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "health-services/facility/src/main/resources/db" image-name: "facility-db" + - name: "builds/health-campaign-services/health-services/facility-java-17" + build: + - work-dir: "health-services/facility" + image-name: "facility" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "health-services/facility/src/main/resources/db" + image-name: "facility-db" - name: "builds/health-campaign-services/health-services/transformer" build: - work-dir: "health-services/transformer" image-name: "transformer" dockerfile: "build/maven/Dockerfile" + - name: "builds/health-campaign-services/health-services/transformer-java-17" + build: + - work-dir: "health-services/transformer" + image-name: "transformer" + dockerfile: "build/17/maven/Dockerfile" - name: "builds/health-campaign-services/core-services/service-request" build: - work-dir: "core-services/service-request" @@ -106,6 +193,13 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "core-services/pgr-services/src/main/resources/db" image-name: "pgr-services-db" + - name: "builds/health-campaign-services/core-services/health-pgr-services" + build: + - work-dir: "core-services/pgr-services" + image-name: "health-pgr-services" + dockerfile: "build/maven/Dockerfile" + - work-dir: "core-services/pgr-services/src/main/resources/db" + image-name: "health-pgr-services-db" - name: "builds/health-campaign-services/core-services/user-otp" build: - work-dir: "core-services/user-otp" @@ -114,3 +208,82 @@ config: build: - work-dir: "core-services/egov-notification-mail" image-name: "egov-notification-mail" + - name: "builds/health-campaign-services/core-services/attendance" + build: + - work-dir: "core-services/attendance" + image-name: "attendance" + dockerfile: "build/maven/Dockerfile" + - work-dir: "core-services/attendance/src/main/resources/db" + image-name: "attendance-db" + - name: "builds/health-campaign-services/core-services/health-hrms" + build: + - work-dir: "core-services/egov-hrms" + image-name: "health-hrms" + dockerfile: "build/maven/Dockerfile" + - work-dir: "core-services/egov-hrms/src/main/resources/db" + image-name: "health-hrms-db" + - name: "builds/health-campaign-services/core-services/health-hrms-java-17" + build: + - work-dir: "core-services/egov-hrms" + image-name: "health-hrms" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "core-services/egov-hrms/src/main/resources/db" + image-name: "health-hrms-db" + - name: "builds/health-campaign-services/core-services/egov-hrms" + build: + - work-dir: "core-services/egov-hrms" + image-name: "egov-hrms" + dockerfile: "build/maven/Dockerfile" + - work-dir: "core-services/egov-hrms/src/main/resources/db" + image-name: "egov-hrms-db" + - name: "builds/health-campaign-services/core-services/egov-hrms-java-17" + build: + - work-dir: "core-services/egov-hrms" + image-name: "egov-hrms" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "core-services/egov-hrms/src/main/resources/db" + image-name: "egov-hrms-db" + - name: "builds/health-campaign-services/health-services/plan-service" + build: + - work-dir: "health-services/plan-service" + image-name: "plan-service" + 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-generator" + build: + - 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 + build: + - work-dir: frontend/micro-ui/ + dockerfile: frontend/micro-ui/web/workbench/Dockerfile + image-name: workbench-ui + + - name: builds/health-campaign-services/frontend/microplan-ui + build: + - work-dir: frontend/micro-ui/ + dockerfile: frontend/micro-ui/web/microplan/Dockerfile + image-name: microplan-ui + +#Utilities + - name: "builds/health-campaign-services/health-services/project-factory" + build: + - work-dir: "health-services/project-factory" + image-name: "project-factory" + - work-dir: "health-services/project-factory/migration" + image-name: "project-factory-db" diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/AdvanceTableChartResponseHandler.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/AdvanceTableChartResponseHandler.java index dd41cca5179..8b81053c58b 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/AdvanceTableChartResponseHandler.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/AdvanceTableChartResponseHandler.java @@ -12,6 +12,7 @@ import com.tarento.analytics.dto.Plot; import com.tarento.analytics.helper.ComputedFieldFactory; import com.tarento.analytics.helper.IComputedField; +import com.tarento.analytics.helper.SortingHelper; import com.tarento.analytics.model.ComputedFields; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,6 +34,8 @@ public class AdvanceTableChartResponseHandler implements IResponseHandler { @Autowired private ObjectMapper mapper; + @Autowired + private SortingHelper sortingHelper; @Autowired private ComputedFieldFactory computedFieldFactory; @@ -116,6 +119,7 @@ public AggregateDto translate(AggregateRequestDto requestDto, ObjectNode aggrega }); }); + List finalDataList = dataList; mappings.entrySet().stream().forEach(plotMap -> { List plotList = plotMap.getValue().values().stream().collect(Collectors.toList()); //filter out data object with all zero data. @@ -146,7 +150,7 @@ public AggregateDto translate(AggregateRequestDto requestDto, ObjectNode aggrega logger.error("execution of computed field :"+e.getMessage()); } } - dataList.add(data); + finalDataList.add(data); } }); @@ -168,7 +172,11 @@ public AggregateDto translate(AggregateRequestDto requestDto, ObjectNode aggrega }); } } - + + if (chartNode.has("sort")) { + dataList = sortingHelper.tableSort(dataList, chartNode.get("sort").asText()); + } + return getAggregatedDto(chartNode, dataList, requestDto.getVisualizationCode()); } diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java index e72d706caba..cc9f3d87d1f 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java @@ -85,8 +85,8 @@ public AggregateDto translate(AggregateRequestDto requestDto, ObjectNode aggrega if(isPredictionEnabled ){ List aggrNodes = aggregationNode.findValues(CHART_SPECIFIC); - startDate = aggrNodes.get(0).findValues(START_DATE).get(0).findValues("key").get(0).asLong(); - endDate = aggrNodes.get(0).findValues(END_DATE).get(0).findValues("key").get(0).asLong(); + startDate = (aggrNodes.get(0).findValues(START_DATE).get(0).findValues("key").get(0).asLong()/86400000)*86400000; + endDate = (aggrNodes.get(0).findValues(END_DATE).get(0).findValues("key").get(0).asLong()/86400000)*86400000; interval=Constants.Interval.day.toString(); addTargetDates(startDate, endDate,targetEpochKeys); } @@ -117,7 +117,7 @@ public AggregateDto translate(AggregateRequestDto requestDto, ObjectNode aggrega Set finalBucketKeys = new LinkedHashSet<>(); // For multi aggr, find all plot keys first - enrichBucketKeys(aggrNodes, finalBucketKeys, interval); + enrichBucketKeys(aggrNodes, finalBucketKeys, interval, startDate, isPredictionEnabled); initializeMultiAggrPlotMap(multiAggrPlotMap, finalBucketKeys); for(JsonNode aggrNode : aggrNodes) { @@ -125,6 +125,9 @@ public AggregateDto translate(AggregateRequestDto requestDto, ObjectNode aggrega ArrayNode buckets = (ArrayNode) aggrNode.findValues(IResponseHandler.BUCKETS).get(0); for(JsonNode bucket : buckets){ JsonNode bkey = bucket.findValue(IResponseHandler.KEY); + if (isPredictionEnabled && Long.parseLong(bkey.asText()) < startDate) { + continue; + } String key = getIntervalKey(bkey.asText(), Constants.Interval.valueOf(interval)); plotKeys.add(key); if(isPredictionEnabled && !headerPath.equals(predictionPath)){ @@ -240,7 +243,7 @@ public AggregateDto translate(AggregateRequestDto requestDto, ObjectNode aggrega private void appendActualPlot(List actualEpochKeys, Long finalStartDate, Data data, String symbol, boolean isCumulative) { Long actualStartDate = actualEpochKeys.get(0); Double differenceInDays = Math.ceil((actualStartDate - finalStartDate) / Constants.DAY_EPOCH); - for (int i = 0; i < differenceInDays; i++) { + for (int i = 0; i < differenceInDays + 1; i++) { String name = getIntervalKey(String.valueOf(finalStartDate + Constants.DAY_EPOCH*i), Constants.Interval.day); data.getPlots().add(i,new Plot(name,0.0,symbol)); } @@ -354,13 +357,16 @@ private void initializeMultiAggrPlotMap(Map multiAggrPlotMap, Se }); } - private void enrichBucketKeys(List aggrNodes, Set finalBucketKeys, String interval) { + private void enrichBucketKeys(List aggrNodes, Set finalBucketKeys, String interval, Long startDate, Boolean isPredictionEnabled) { List bkeyList = new ArrayList<>(); for(JsonNode aggrNode : aggrNodes) { if (aggrNode.findValues(IResponseHandler.BUCKETS).size() > 0) { ArrayNode buckets = (ArrayNode) aggrNode.findValues(IResponseHandler.BUCKETS).get(0); for(JsonNode bucket : buckets){ String bkey = bucket.findValue(IResponseHandler.KEY).asText(); + if (isPredictionEnabled && Long.parseLong(bkey) < (startDate)) { + continue; + } bkeyList.add(bkey); } } diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/MetricChartResponseHandler.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/MetricChartResponseHandler.java index be03e77a56d..c7c7b67a486 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/MetricChartResponseHandler.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/MetricChartResponseHandler.java @@ -59,7 +59,7 @@ public class MetricChartResponseHandler implements IResponseHandler{ @Override public AggregateDto translate(AggregateRequestDto request, ObjectNode aggregations) throws IOException { List dataList = new ArrayList<>(); - String requestId = request.getRequestId(); + String requestId = request.getRequestId(); String visualizationCode = request.getVisualizationCode(); JsonNode aggregationNode = aggregations.get(AGGREGATIONS); @@ -203,9 +203,20 @@ public AggregateDto translate(AggregateRequestDto request, ObjectNode aggregatio data.setPlots( Arrays.asList(latestDateplot,lastUpdatedTime)); request.getResponseRecorder().put(visualizationCode, request.getModuleLevel(), data); dataList.add(data); - if(chartNode.get(POST_AGGREGATION_THEORY) != null) { + if(chartNode.get(POST_AGGREGATION_THEORY) != null) { ComputeHelper computeHelper = computeHelperFactory.getInstance(chartNode.get(POST_AGGREGATION_THEORY).asText()); - computeHelper.compute(request, dataList); +// computeHelper.compute(request, dataList); + List capDataList = new ArrayList<>(); + + if (chartNode.has(IS_CAPPED_BY_CAMPAIGN_PERIOD)) { + List valueNode = aggregationNode.findValues(chartNode.get(IS_CAPPED_BY_CAMPAIGN_PERIOD).get(0).asText()); + if(valueNode.size() > 0) { + Long val = valueNode.get(0).get(IResponseHandler.VALUE).asLong(); + Data dataNode = new Data(aggrsPaths.get(0).asText(), val.doubleValue(), chartNode.get(IResponseHandler.VALUE_TYPE).asText()); + capDataList.add(dataNode); + } + } + computeHelper.compute(request, dataList, capDataList); } }catch (Exception e){ logger.info("data chart name = "+chartName +" ex occurred "+e.getMessage()); diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/AdditiveComputedField.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/AdditiveComputedField.java index 92ba43883b9..e5c8f5349b9 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/AdditiveComputedField.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/AdditiveComputedField.java @@ -1,6 +1,8 @@ package com.tarento.analytics.helper; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; import com.tarento.analytics.dto.AggregateRequestDto; import com.tarento.analytics.dto.Data; import com.tarento.analytics.dto.Plot; @@ -9,12 +11,14 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; import static com.tarento.analytics.handler.IResponseHandler.HIDE_HEADER_DENOMINATION; +import static com.tarento.analytics.handler.IResponseHandler.IS_CAPPED_BY_CAMPAIGN_PERIOD; @Component public class AdditiveComputedField implements IComputedField { @@ -40,16 +44,31 @@ public void add(Data data, List fields, String newField,JsonNode chartNo Map plotMap = data.getPlots().stream().collect(Collectors.toMap(Plot::getName, Function.identity())); double total = 0.0; + double capTotal = 0.0; for (String field: fields){ if(plotMap.containsKey(field)){ dataType = plotMap.get(field).getSymbol(); + if(chartNode.has(IS_CAPPED_BY_CAMPAIGN_PERIOD) && doesTextExistInArrayNode((ArrayNode) chartNode.get(IS_CAPPED_BY_CAMPAIGN_PERIOD), field)) continue; total = total+ plotMap.get(field).getValue(); } } if(postAggrTheoryName != null && !postAggrTheoryName.isEmpty()) { ComputeHelper computeHelper = computeHelperFactory.getInstance(postAggrTheoryName); + if (chartNode.has(IS_CAPPED_BY_CAMPAIGN_PERIOD)) { + List commonStrings = new ArrayList<>(); + chartNode.get(IS_CAPPED_BY_CAMPAIGN_PERIOD).forEach( + item -> { + if (fields.contains(item.asText())) { + commonStrings.add(item.asText()); + } + } + ); + if(commonStrings.size()>0) { + capTotal = commonStrings.stream().mapToDouble(commonString -> plotMap.get(commonString).getValue()).sum(); + } + } - total = computeHelper.compute(aggregateRequestDto,total ); + total = computeHelper.compute(aggregateRequestDto,total,capTotal ); } @@ -62,5 +81,15 @@ public void add(Data data, List fields, String newField,JsonNode chartNo } } + private static boolean doesTextExistInArrayNode(ArrayNode arrayNode, String searchText) { + for (JsonNode element : arrayNode) { + if (element.isTextual()) { + String text = element.asText(); + if (text.equals(searchText)) { + return true; + } + } + } + return false; + } } - diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/ComputeHelper.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/ComputeHelper.java index 3c50469fe94..f6a853dfd35 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/ComputeHelper.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/ComputeHelper.java @@ -12,8 +12,9 @@ * */ public interface ComputeHelper { - public List compute(AggregateRequestDto request, List data); + public List compute(AggregateRequestDto request, List data, List capValues); public Double compute(AggregateRequestDto request, double value); + public Double compute(AggregateRequestDto request, double value, double capTotal); } diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/NoOpsComputedField.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/NoOpsComputedField.java index b9715b43a50..9f6c83b0aca 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/NoOpsComputedField.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/NoOpsComputedField.java @@ -15,6 +15,7 @@ import java.util.List; import static com.tarento.analytics.constant.Constants.PostAggregationTheories.RESPONSE_DIFF_DATES; +import static com.tarento.analytics.handler.IResponseHandler.IS_CAPPED_BY_CAMPAIGN_PERIOD; @Component public class NoOpsComputedField implements IComputedField{ @@ -37,6 +38,7 @@ public void set(AggregateRequestDto requestDto, String postAggrTheoryName){ public void add(ObjectNode data, List fields, String newField, JsonNode chartNode ) { ObjectNode noOpsNode = JsonNodeFactory.instance.objectNode(); List dataList = new ArrayList<>(); + List capDataList = new ArrayList<>(); try { List values = data.findValues(fields.get(0)); if (postAggrTheoryName.equalsIgnoreCase(RESPONSE_DIFF_DATES)) { @@ -45,8 +47,14 @@ public void add(ObjectNode data, List fields, String newField, JsonNode Data dataNode = new Data(fields.get(0), val.doubleValue(), chartNode.get(IResponseHandler.VALUE_TYPE).asText()); dataList.add(dataNode); } + + if (chartNode.has(IS_CAPPED_BY_CAMPAIGN_PERIOD) && data.has((chartNode.get(IS_CAPPED_BY_CAMPAIGN_PERIOD).get(0).asText()))) { + Long capValue = data.findValues(chartNode.get(IS_CAPPED_BY_CAMPAIGN_PERIOD).get(0).asText()).get(0).get(IResponseHandler.VALUE).asLong(); + Data dataNode = new Data(fields.get(0), capValue.doubleValue(), chartNode.get(IResponseHandler.VALUE_TYPE).asText()); + capDataList.add(dataNode); + } ComputeHelper computeHelper = computeHelperFactory.getInstance(RESPONSE_DIFF_DATES); - List computedData = computeHelper.compute(aggregateRequestDto, dataList); + List computedData = computeHelper.compute(aggregateRequestDto, dataList, capDataList); noOpsNode.put(IResponseHandler.VALUE, ((Double) computedData.get(0).getHeaderValue()).longValue()); data.set(newField, noOpsNode); } diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/SortingHelper.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/SortingHelper.java index fcd11c1f943..5101bfa72df 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/SortingHelper.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/SortingHelper.java @@ -2,7 +2,6 @@ import org.springframework.stereotype.Component; import com.tarento.analytics.dto.Data; import com.tarento.analytics.dto.Plot; -import java.util.*; import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -21,6 +20,11 @@ public List sort(String sortingKey, List dataList) { } return dataList; } + public List tableSort(List dataList, String sortingKey) { + Comparator tableSortComparator = tableSortComparator(sortingKey); + dataList.sort(tableSortComparator); + return dataList; + } private static Comparator plotSortComparator(String sortingKey, Boolean isValueSortingApplicable) { return new Comparator() { @@ -48,4 +52,18 @@ public int compare(Plot p1, Plot p2) { }; } + private static Comparator tableSortComparator(String sortingKey) { + return (p1, p2) -> { + String plotName1 = p1.getHeaderName().toUpperCase(); + String plotName2 = p2.getHeaderName().toUpperCase(); + + if (sortingKey.equals(SORT_KEY_ASC)) { + return plotName1.compareTo(plotName2); + } else if (sortingKey.equals(SORT_KEY_DESC)) { + return plotName2.compareTo(plotName1); + } + return 0; + }; + } + } \ No newline at end of file diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/TargetPerDateComputeHelper.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/TargetPerDateComputeHelper.java index ce05e5c26d4..8c99870ac86 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/TargetPerDateComputeHelper.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/TargetPerDateComputeHelper.java @@ -46,14 +46,6 @@ public List compute(AggregateRequestDto request, List data) { Long dateDifference = TimeUnit.DAYS.convert((eDate - sDate), TimeUnit.MILLISECONDS); if(dateDifference == 0l) dateDifference = dateDifference + 1l ; - if(request.getChartNode().get(IS_CAPPED_BY_CAMPAIGN_PERIOD) != null && request.getChartNode().get(IS_CAPPED_BY_CAMPAIGN_PERIOD).asBoolean()){ - if(request.getFilters()!=null && request.getFilters().containsKey(CAMPAIGN_START_DATE) && request.getFilters().containsKey(CAMPAIGN_END_DATE)) { - Long campaignStartDate = Long.parseLong(String.valueOf(request.getFilters().get(CAMPAIGN_START_DATE))); - Long campaignEndDate = Long.parseLong(String.valueOf(request.getFilters().get(CAMPAIGN_END_DATE))); - Long campaignDateDifference = TimeUnit.DAYS.convert((campaignEndDate - campaignStartDate), TimeUnit.MILLISECONDS); - dateDifference = Math.min(dateDifference, campaignDateDifference); - } - } for(Data eachData : data) { Double value = (Double) eachData.getHeaderValue(); logger.info("Value is : " + value + " :: Date Difference is : " + dateDifference); @@ -67,6 +59,49 @@ public List compute(AggregateRequestDto request, List data) { return data; } + + @Override + public List compute(AggregateRequestDto request, List data, List capValues) { + if(request.getRequestDate()!= null && request.getRequestDate().getStartDate() != null && request.getRequestDate().getEndDate() != null) { + try { + Long sDate = Long.parseLong(request.getRequestDate().getStartDate()); + logger.info("Start Date : " + String.valueOf(sDate)); + Long eDate = Long.parseLong(request.getRequestDate().getEndDate()); + logger.info("End Date : " + String.valueOf(eDate)); + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date(eDate)); + if(cal.get(Calendar.HOUR_OF_DAY) == LAST_HOUR && cal.get(Calendar.MINUTE) == LAST_MINUTE) { + eDate = eDate + ROUND_OFF; + } + logger.info("End Date after Round Off: " + String.valueOf(eDate)); + Long dateDifference = TimeUnit.DAYS.convert((eDate - sDate), TimeUnit.MILLISECONDS); + if(dateDifference == 0l) dateDifference = dateDifference + 1l ; + + for(Data eachData : data) { + Double value = (Double) eachData.getHeaderValue(); + logger.info("Value is : " + value + " :: Date Difference is : " + dateDifference); + if(request.getChartNode().get(IS_CAPPED_BY_CAMPAIGN_PERIOD) != null && capValues.size()>0){ + if(request.getFilters()!=null && request.getFilters().containsKey(CAMPAIGN_START_DATE) && request.getFilters().containsKey(CAMPAIGN_END_DATE)) { + Long campaignStartDate = Long.parseLong(String.valueOf(request.getFilters().get(CAMPAIGN_START_DATE))); + Long campaignEndDate = Long.parseLong(String.valueOf(request.getFilters().get(CAMPAIGN_END_DATE))); + Long campaignDateDifference = TimeUnit.DAYS.convert((campaignEndDate - campaignStartDate), TimeUnit.MILLISECONDS); + if (dateDifference >= campaignDateDifference) { + Double capValue = (Double) capValues.get(0).getHeaderValue(); + eachData.setHeaderValue(capValue); + continue; + } + } + } + value = (value / NUMBER_OF_DAYS) * dateDifference; + eachData.setHeaderValue(value); + } + } catch (Exception ex) { + logger.error("Encountered an error while computing the logic in Target Date Computer : " + ex.getMessage()); + } + } + return data; + } + @Override public Double compute(AggregateRequestDto request, double value){ @@ -97,6 +132,49 @@ public Double compute(AggregateRequestDto request, double value){ + } + + @Override + public Double compute(AggregateRequestDto request, double value, double capTotal){ + + if(request.getRequestDate()!= null && request.getRequestDate().getStartDate() != null && request.getRequestDate().getEndDate() !=null) { + try { + Long sDate = Long.parseLong(request.getRequestDate().getStartDate()); + logger.info("Start Date : " + String.valueOf(sDate)); + Long eDate = Long.parseLong(request.getRequestDate().getEndDate()); + logger.info("End Date : " + String.valueOf(eDate)); + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date(eDate)); + if(cal.get(Calendar.HOUR_OF_DAY) == LAST_HOUR && cal.get(Calendar.MINUTE) == LAST_MINUTE) { + eDate = eDate + ROUND_OFF; + } + logger.info("End Date after Round Off: " + String.valueOf(eDate)); + Long dateDifference = TimeUnit.DAYS.convert((eDate - sDate), TimeUnit.MILLISECONDS); + if(dateDifference == 0l) dateDifference = dateDifference + 1l ; + + value = (value / NUMBER_OF_DAYS) * dateDifference; + + if(request.getChartNode().get(IS_CAPPED_BY_CAMPAIGN_PERIOD) != null ){ + if(request.getFilters()!=null && request.getFilters().containsKey(CAMPAIGN_START_DATE) && request.getFilters().containsKey(CAMPAIGN_END_DATE)) { + Long campaignStartDate = Long.parseLong(String.valueOf(request.getFilters().get(CAMPAIGN_START_DATE))); + Long campaignEndDate = Long.parseLong(String.valueOf(request.getFilters().get(CAMPAIGN_END_DATE))); + Long campaignDateDifference = TimeUnit.DAYS.convert((campaignEndDate - campaignStartDate), TimeUnit.MILLISECONDS); + if (dateDifference >= campaignDateDifference) { + value = capTotal; + } + } + } + logger.info("Value is : " + value + " :: Date Difference is : " + dateDifference); + + } catch (Exception ex) { + logger.error("Encountered an error while computing the logic in Target Date Computer : " + ex.getMessage()); + } + } + + return value; + + + } } diff --git a/core-services/egov-hrms/CHANGELOG.md b/core-services/egov-hrms/CHANGELOG.md new file mode 100644 index 00000000000..79728eda4ce --- /dev/null +++ b/core-services/egov-hrms/CHANGELOG.md @@ -0,0 +1,45 @@ +# Changelog +All notable changes to this module will be documented in this file. + +## 1.2.7 - 2024-05-29 +- Integrated Boundary v2 functionality +- Individual model copied and replicated to the 2.9 version +- Upgraded Flyway base image version to 10.7.1 for DB Migration + +## 1.2.6 - 2024-03-06 +- Added client Referenceid to Individual to avoid errors during down sync in APK + +## 1.2.5 - 2023-02-02 + +- Transition from 1.2.5-beta version to 1.2.5 version + +## 1.2.5-beta - 2022-03-02 +- Added security fix for restricting employee search from citizen role + +## 1.2.4 - 2022-01-13 +- Updated to log4j2 version 2.17.1 + +## 1.2.3 - 2021-07-26 + - Fixed RAIN-3056: Able to re-activate employee by selecting the previous date + +## 1.2.2 - 2021-05-11 + - VUL-WEB-L008 + - Added @SafeHtml annotaion on string fields + - Updated POM to add safeHtml validator libraries + +## 1.2.1 - 2021-02-26 +- Updated domain name in application.properties + +## 1.2.0 - 2021-01-12 +- Added employee reactivation feature + +## 1.1.0 - 2020-05-27 + +- Upgraded to `tracer:2.0.0-SNAPSHOT` +- Upgraded to `Spring boot 2.2.6` +- Renamed `ReferenceType` enum to `EmployeeDocumentReferenceType` +- Added typescript interface generation plugin + +## 1.0.0 + +- Base version diff --git a/core-services/egov-hrms/LOCALSETUP.md b/core-services/egov-hrms/LOCALSETUP.md new file mode 100644 index 00000000000..275a5420e3c --- /dev/null +++ b/core-services/egov-hrms/LOCALSETUP.md @@ -0,0 +1,46 @@ +# Local Setup + +To setup the egov-hrms service in your local system, clone the [Core Service repository](https://github.com/egovernments/core-services). + +## Dependencies + +### Infra Dependency + +- [x] Postgres DB +- [ ] Redis +- [ ] Elasticsearch +- [x] Kafka + - [ ] Consumer + - [x] Producer + +## Running Locally + +To run the egov-hrms services in local system, you need to port forward below services. + +```bash +function kgpt(){kubectl get pods -n egov --selector=app=$1 --no-headers=true | head -n1 | awk '{print $1}'} +kubectl port-forward -n egov $(kgpt egov-idgen) 8087:8080 & +kubectl port-forward -n egov $(kgpt egov-mdms-service) 8088:8080 & +kubectl port-forward -n egov $(kgpt egov-user) 8089:8080 & +kubectl port-forward -n egov $(kgpt egov-filestore) 8090:8080 & +kubectl port-forward -n egov $(kgpt egov-localization) 8091:8080 & +``` + +Update below listed properties in `application.properties` before running the project: + +```ini +# {Id Gen service hostname} +egov.idgen.host = http://127.0.0.1:8087 + +# {mdms hostname} +egov.mdms.host=http://127.0.0.1:8088 + +# {user service hostname} +egov.user.host = http://127.0.0.1:8089 + +# {Filestore service hostname} +egov.filestore.host = http://127.0.0.1:8090 + +# {Localization service hostname} +egov.localization.host = http://127.0.0.1:8091 +``` diff --git a/core-services/egov-hrms/README.md b/core-services/egov-hrms/README.md new file mode 100644 index 00000000000..ceb2f235664 --- /dev/null +++ b/core-services/egov-hrms/README.md @@ -0,0 +1,112 @@ +# Egov-HRMS Service +### HRMS Service +The objective of HRMS is to provide a service that manages all the employees enrolled onto the system. HRMS provides extensive APIs to create, update and search the employees with attributes like assignments, service history, jurisdiction etc. HRMS can be treated a sub-set of the egov-user service, Every employee created through HRMS will also be created as a user in egov-user. + +### DB UML Diagram + +- NA + +### Service Dependencies +- egov-user +- egov-localization +- egov-idgen +- egov-mdms +- egov-filestore + +### Swagger API Contract +- Please refer to the [Swagger API contarct](https://editor.swagger.io/?url=https://raw.githubusercontent.com/egovernments/business-services/master/Docs/hrms-v1.0.0.yaml#!/) for HRMS service to understand the structure of APIs and to have visualization of all internal APIs. + + +## Service Details +**Details of all the entities involved:** + +**a) Assignments:** Every employee is assigned a list of assignments, every assignment is a designation provided to that employee for a given period of time. These designations are mapped to departments. This also includes marking the employee as HOD for that dept if needed. Employee can also provide information on who does he report to. + + - **Constraints:** + 1. For a given period of time an employee shouldn't have more than one assignments. + 2. The department and designation part of the employee must be configured in the system. + 3. Details of assignment once entered in the system cannot be deleted. + 4. An employee cannot have more than one active assignment. + +**b) Jurisdictions:** A jurisdiction is a area of power for any employee. It can be a zone, ward, block, city, state or the country. Currently a jurisdiction is defined as combination of Hierarchy type, Boundary Type and the actual Boundary. However, in the current system we are not validating these jurisdictions. This is being collected only for the sake of data. + + - **Constraints:** + 1. The details pertaining to a jurisdiction like Hierarchy, Boundary Type and Boundary must be configured in the system. + 2. An employee can have more than one jurisdictions. + 3. Currently in the system jurisdiction is limited to within a ULB. + +**c) Service History:** Service history is the record of an employee's professional experience. It captures information about location and period of work with necessary order number. Information about the current work details are to be entered here. + + - **Constraints:** + 1. There's no rule on period, dates of different services can overlap. + 2. There's no cap on the number of entries in the service history. + 3. Captured as legacy data. + +**d) Educational Details:** Captures educational details of the employee. Captures information like Degree, Year of Passing, University, Specialization etc as part of the educational details. + + - **Constraints:** + 1. Details pertaining to educational details like Degree, Specialization must be configured. + + +**e) Departmental Tests:** Captures details of the tests undertaken by the employee. Like name of the test and year of passing. + + - **Constraints:** + 1. Test details must be configures in the system. + +**f) Deactivation Details:** Details of deactivation of the employee, which captures reason for deactivation, period of deactivation and other necessary details. + + - **Constraints:** + 1. Deactivation details are compulsory while deactivating an employee. + +**f) Reactivation Details:** Details of reactivation of the employee, which captures reason for reactivation, the effective date from when reactivation take place and other necessary details. + + - **Constraints:** + 1. Reactivation details are compulsory while reactivating an employee. + + + +**Uniqueness Constraints:** +- Employee code has to be unique and will be used as username for login. +- Phone number has to be unique, which means no 2 employees can have the same phone number. + + + +**Notification:** +- Notification is sent to the phone number of the employee who has been created in the system. This is an SMS notification. + +### Configurable properties + +| Environment Variables | Description | Value | +| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------| +| `egov.hrms.employee.app.link` | This is the link to the mseva app, which differs based on the environment. | https://mseva.lgpunjab.gov.in/employee/user/login | +| `egov.hrms.default.pagination.limit` | This is the pagination limit on search results of employee search, it can be set to any numeric value without decimals. | 200 | +| `egov.hrms.default.pwd.length` | This is the length of password to be generated at the time of employee creation. However, please ensure this is in sync with the egov-user pwd policy. | 10 | +| `open.search.enabled.roles` | This is a list of Role codes that are allowed to perform an open-search in hrms. | SUPERUSER,ADMIN | +| `egov.idgen.ack.name` | Key to be configured in Idgen alongwith the ID format to generate employee code. | hrms.employeecode | +| `egov.idgen.ack.format` | Format to be configured in ID gen to generate employee code. | EMP-[city]-[SEQ_EG_HRMS_EMP_CODE] | +### API Details + +`BasePath` /egov-hrms/employees/[API endpoint] + +##### Method +**a) Create Employee `POST /_create` :** API (Bulk API) to create an employee with the following details: Assignments, Jurisdictions, Service History, Educational Details, Departmental Tests + +**b) Update Employee `POST /_update` :** API (Bulk API) to update the details of an employee with the following details: Assignments, Jurisdictions, Service History, Educational Details, Departmental Tests. There are constraints under which the update works, which are listed in the details of entities. As part of the personal details of the employee, Code of the employee cannot be updated once created. + +Deactivation is a part of the update API where the employee is marked inactive. This marks the user entry of this employee also as inactive. While deactivating an employee it is mandatory to provide deactivation details as well. + +**c) Search Employee `POST /_search` :** API to search the employee in the system on the following criteria: Id, UUID, Name, Code, Status, Type, Department, Designation, Position. All of them being arrays, at a time more than one employees can be fetched. +Constraints: a. Open Search is enabled only for a set of users. Currently it is enabled only for SUPERUSER, if it has to be enabled for other roles, add those roles to the parameter 'open.search.enabled.roles' in app.properties with values(role codes) separated by comma. + +**d) Count of Employee `POST /_count` :** This API is use to get list of active and inactive employee present in the system. + +### Kafka Consumers + +- NA + +### Kafka Producers + +- Following are the Producer topic. + - **save-hrms-employee** :- This topic is used to create new employee in the system. + - **update-hrms-employee** :- This topic is used to update the existing employee in the systen. + - **egov.core.notification.sms** :- This topic is used to send noification to the phone number of the employee who has been created in the system. \ No newline at end of file diff --git a/core-services/egov-hrms/egov-hrms.iml b/core-services/egov-hrms/egov-hrms.iml new file mode 100644 index 00000000000..abf9c52d541 --- /dev/null +++ b/core-services/egov-hrms/egov-hrms.iml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/core-services/egov-hrms/pom.xml b/core-services/egov-hrms/pom.xml new file mode 100644 index 00000000000..0a0507aa5a4 --- /dev/null +++ b/core-services/egov-hrms/pom.xml @@ -0,0 +1,177 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + org.egov + egov-hrms + 1.2.7-SNAPSHOT + egov-hrms + HR Management System + + 2.17.1 + UTF-8 + 1.8 + 2.9.6 + UTF-8 + 3.3.9 + 1.18.8 + 2.6 + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework + spring-beans + 5.2.20.RELEASE + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.flywaydb + flyway-core + 9.22.3 + + + org.postgresql + postgresql + + + org.egov.services + services-common + 1.1.1-SNAPSHOT + + + commons-lang + commons-lang + ${commons-lang-version} + + + org.projectlombok + lombok + + + org.springframework.boot + spring-boot-devtools + + + org.springframework + spring-test + test + + + org.springframework.boot + spring-boot-starter-test + test + + + com.google.code.gson + gson + 2.8.0 + + + org.egov + mdms-client + 0.0.2-SNAPSHOT + + + org.egov.services + tracer + 2.1.2-SNAPSHOT + + + org.hibernate + hibernate-validator + 6.0.16.Final + + + org.jsoup + jsoup + 1.10.2 + + + org.egov.common + health-services-models + 1.0.12-SNAPSHOT + compile + + + + + repo.egovernments.org + eGov ERP Releases Repository + https://nexus-repo.egovernments.org/nexus/content/repositories/releases/ + + + repo.egovernments.org.snapshots + eGov ERP Releases Repository + https://nexus-repo.egovernments.org/nexus/content/repositories/snapshots/ + + always + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + org.springframework.boot + spring-boot-devtools + + + + + + cz.habarta.typescript-generator + typescript-generator-maven-plugin + 2.22.595 + + + generate + + generate + + process-classes + + + + jackson2 + + org.egov.hrms.web.contract.EmployeeRequest + org.egov.hrms.web.contract.EmployeeResponse + org.egov.hrms.web.contract.EmployeeSearchCriteria + + + + + org.egov.hrms.web.contract.User:User + org.egov.hrms.model.AuditDetails:AuditDetails + org.egov.common.contract.request.User:User + org.egov.common.contract.request.RequestInfo:RequestInfo + org.egov.common.contract.response.ResponseInfo:ResponseInfo + + Digit + true + module + + + + + diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/EgovEmployeeApplication.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/EgovEmployeeApplication.java new file mode 100644 index 00000000000..12c7c5daeb5 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/EgovEmployeeApplication.java @@ -0,0 +1,120 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms; + +import java.util.TimeZone; + +import javax.annotation.PostConstruct; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.utils.MultiStateInstanceUtil; +import org.egov.hrms.config.PropertiesManager; +import org.egov.hrms.repository.RestCallRepository; +import org.egov.hrms.service.DefaultUserService; +import org.egov.hrms.service.IndividualService; +import org.egov.hrms.service.UserService; +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.context.annotation.Primary; + +@SpringBootApplication +@ComponentScan(basePackages = { "org.egov.hrms", "org.egov.hrms.web.controller" , "org.egov.hrms.config"}) +@Import({TracerConfiguration.class, MultiStateInstanceUtil.class}) +@Slf4j +public class EgovEmployeeApplication { + + @Value("${app.timezone}") + private String timeZone; + + @PostConstruct + public void initialize() { + TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); + } + + @Bean + public ObjectMapper getObjectMapper() { + final ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + objectMapper.setTimeZone(TimeZone.getTimeZone(timeZone)); + return objectMapper; + } + + @Bean + @Primary + public UserService getUserService(@Value("${egov.hrms.user.service.qualifier}") String userServiceQualifier, + @Autowired PropertiesManager propertiesManager, + @Autowired RestCallRepository restCallRepository, + @Autowired ObjectMapper objectMapper, + @Autowired MultiStateInstanceUtil multiStateInstanceUtil, + @Value("${egov.user.create.endpoint}") String userCreateEndpoint, + @Value("${egov.user.update.endpoint}") String userUpdateEndpoint, + @Value("${egov.user.search.endpoint}") String userSearchEndpoint) { + if (userServiceQualifier.equalsIgnoreCase("individualService")) { + log.info("using individual module as user service"); + return new IndividualService(propertiesManager, restCallRepository); + } + else { + log.info("using egov-user module as user service"); + DefaultUserService userService = new DefaultUserService(); + userService.setPropertiesManager(propertiesManager); + userService.setRestCallRepository(restCallRepository); + userService.setObjectMapper(objectMapper); + userService.setCentralInstanceUtil(multiStateInstanceUtil); + userService.setUserCreateEndpoint(userCreateEndpoint); + userService.setUserUpdateEndpoint(userUpdateEndpoint); + userService.setUserSearchEndpoint(userSearchEndpoint); + return userService; + } + } + + public static void main(String[] args) { + SpringApplication.run(EgovEmployeeApplication.class, args); + } +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java new file mode 100644 index 00000000000..1f0522f0d36 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java @@ -0,0 +1,143 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.empernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@empernments.org. + */ + +package org.egov.hrms.config; + +import lombok.*; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class PropertiesManager { + + //Hosts and Endpoints + @Value("${egov.mdms.host}") + public String mdmsHost; + + @Value("${egov.mdms.search.endpoint}") + public String mdmsSearchEndpoint; + + @Value("${egov.user.host}") + public String userHost; + + @Value("${egov.user.search.endpoint}") + public String userSearchEndpoint; + + @Value("${egov.user.create.endpoint}") + public String userCreateEndpoint; + + @Value("${egov.user.update.endpoint}") + public String userUpdateEndpoint; + + @Value("${egov.localization.host}") + public String localizationHost; + + @Value("${egov.localization.search.endpoint}") + public String localizationSearchEndpoint; + + @Value("${egov.idgen.host}") + public String idGenHost; + + @Value("${egov.idgen.path}") + public String idGenEndpoint; + + + //Kafka Topics + @Value("${kafka.topics.save.service}") + public String saveEmployeeTopic; + + @Value("${kafka.topics.update.service}") + public String UpdateEmployeeTopic; + + @Value("${kafka.topics.notification.sms}") + public String coreNotificationTopic; + + @Value("${kafka.topics.hrms.updateData}") + public String updateTopic; + + + //Variables + @Value("${egov.idgen.ack.name}") + public String hrmsIdGenKey; + + @Value("${egov.idgen.ack.format}") + public String hrmsIdGenFormat; + + @Value("${open.search.enabled.roles}") + public String openSearchEnabledRoles; + + @Value("${state.level.tenant.id}") + public String stateLevelTenantId; + + @Value("${parent.level.tenant.id}") + private String parentLevelTenantId; + + @Value("${decryption.abac.enable}") + private Boolean isDecryptionEnable; + + @Value("${egov.individual.host}") + private String individualHost; + + @Value("${egov.individual.create.endpoint}") + private String individualCreateEndpoint; + + @Value("${egov.individual.update.endpoint}") + private String individualUpdateEndpoint; + + @Value("${egov.individual.delete.endpoint}") + private String individualDeleteEndpoint; + + @Value("${egov.individual.search.endpoint}") + private String individualSearchEndpoint; + + @Value("${egov.hrms.auto.generate.password}") + private boolean autoGeneratePassword; + + @Value("${egov.boundary.host}") + private String boundaryServiceHost; + + @Value("${egov.boundary.search.url}") + private String boundarySearchUrl; +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/consumer/HrmsConsumer.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/consumer/HrmsConsumer.java new file mode 100644 index 00000000000..a4c33b0c096 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/consumer/HrmsConsumer.java @@ -0,0 +1,47 @@ +package org.egov.hrms.consumer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.admin.NewTopic; +import org.egov.hrms.config.PropertiesManager; +import org.egov.hrms.producer.HRMSProducer; +import org.egov.hrms.service.NotificationService; +import org.egov.hrms.web.contract.EmployeeRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Component; + +import java.util.HashMap; + +@Component +@Slf4j +public class HrmsConsumer { + + @Autowired + private NotificationService notificationService; + + @Autowired + private ObjectMapper mapper; + + @Autowired + private HRMSProducer hrmsProducer; + + @Autowired + private PropertiesManager propertiesManager; + + @KafkaListener(topics = {"${kafka.topics.hrms.updateData}"}) + public void listenUpdateEmployeeData(final HashMap record,@Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + EmployeeRequest employeeRequest = mapper.convertValue(record, EmployeeRequest.class); + hrmsProducer.push(propertiesManager.getUpdateEmployeeTopic(), employeeRequest); + notificationService.sendReactivationNotification(employeeRequest); + } catch (final Exception e) { + + log.error("Error while listening to value: " + record + " on topic: " + topic + ": ", e); + } + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Assignment.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Assignment.java new file mode 100644 index 00000000000..9df7a4b92bd --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Assignment.java @@ -0,0 +1,96 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; +import javax.validation.constraints.NotNull; + +import org.hibernate.validator.constraints.SafeHtml; +import org.springframework.validation.annotation.Validated; + +@Validated +@EqualsAndHashCode(exclude = {"auditDetails"}) +@AllArgsConstructor +@Builder +@Getter +@NoArgsConstructor +@Setter +@ToString +public class Assignment { + + @SafeHtml + private String id; + + private Long position; + + @SafeHtml + @NotNull + private String designation; + + @SafeHtml + @NotNull + private String department; + + @NotNull + private Long fromDate; + + private Long toDate; + + @SafeHtml + private String govtOrderNumber; + + @SafeHtml + private String tenantid; + + @SafeHtml + private String reportingTo; + + @JsonProperty("isHOD") + private Boolean isHOD=false; + + @NotNull + @JsonProperty("isCurrentAssignment") + private Boolean isCurrentAssignment; + + private AuditDetails auditDetails; + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/AuditDetails.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/AuditDetails.java new file mode 100644 index 00000000000..bb368cd9852 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/AuditDetails.java @@ -0,0 +1,25 @@ +package org.egov.hrms.model; + +import lombok.*; + +import javax.validation.constraints.NotNull; + + +@AllArgsConstructor +@Builder +@Getter +@NoArgsConstructor +@Setter +@ToString +public class AuditDetails { + + private String createdBy; + + private Long createdDate; + + private String lastModifiedBy; + + private Long lastModifiedDate; + + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/DeactivationDetails.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/DeactivationDetails.java new file mode 100644 index 00000000000..32b7787825f --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/DeactivationDetails.java @@ -0,0 +1,45 @@ +package org.egov.hrms.model; + +import lombok.*; +import org.hibernate.validator.constraints.SafeHtml; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; + +@Validated +@EqualsAndHashCode(exclude = {"auditDetails"}) +@AllArgsConstructor +@Getter +@NoArgsConstructor +@Setter +@ToString +@Builder +public class DeactivationDetails { + + @SafeHtml + private String id; + + @SafeHtml + @NotNull + private String reasonForDeactivation; + + @SafeHtml + private String orderNo; + + @SafeHtml + private String remarks; + + @NotNull + private Long effectiveFrom; + + @SafeHtml + private String tenantId; + + private AuditDetails auditDetails; + + + + +} + + diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/DepartmentalTest.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/DepartmentalTest.java new file mode 100644 index 00000000000..6341ce3893a --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/DepartmentalTest.java @@ -0,0 +1,80 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model; + +import lombok.*; + +import javax.validation.constraints.NotNull; + +import org.hibernate.validator.constraints.SafeHtml; +import org.springframework.validation.annotation.Validated; + +@Validated +@EqualsAndHashCode(exclude = {"auditDetails"}) +@Builder +@AllArgsConstructor +@Getter +@NoArgsConstructor +@Setter +@ToString +public class DepartmentalTest { + + @SafeHtml + private String id; + + @SafeHtml + @NotNull + private String test; + + @NotNull + private Long yearOfPassing; + + @SafeHtml + private String remarks; + + @SafeHtml + private String tenantId; + + private AuditDetails auditDetails; + + private Boolean isActive; + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/EducationalQualification.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/EducationalQualification.java new file mode 100644 index 00000000000..2071915c165 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/EducationalQualification.java @@ -0,0 +1,88 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model; + +import lombok.*; + +import javax.validation.constraints.NotNull; + +import org.hibernate.validator.constraints.SafeHtml; +import org.springframework.validation.annotation.Validated; + +@Validated +@EqualsAndHashCode(exclude = {"auditDetails"}) +@Builder +@AllArgsConstructor +@Getter +@NoArgsConstructor +@Setter +@ToString +public class EducationalQualification { + + @SafeHtml + private String id; + + @SafeHtml + @NotNull + private String qualification; + + @SafeHtml + @NotNull + private String stream; + + @NotNull + private Long yearOfPassing; + + @SafeHtml + private String university; + + @SafeHtml + private String remarks; + + @SafeHtml + private String tenantId; + + private AuditDetails auditDetails; + + private Boolean isActive; + + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Employee.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Employee.java new file mode 100644 index 00000000000..f6a9b5cd59a --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Employee.java @@ -0,0 +1,133 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model; + +import lombok.*; +import org.egov.hrms.web.contract.User; +import org.hibernate.validator.constraints.NotEmpty; +import org.hibernate.validator.constraints.SafeHtml; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.ArrayList; +import java.util.List; + +@Validated +@AllArgsConstructor +@EqualsAndHashCode +@Getter +@NoArgsConstructor +@Setter +@ToString +@Builder +public class Employee { + + private Long id; + + @SafeHtml + @Size(max = 1024) + private String uuid; + + @SafeHtml + @Size(min = 1, max = 256) + private String code; + + @SafeHtml + @Size(max = 250) + private String employeeStatus; + + @SafeHtml + @NotNull + @Size(max = 250) + private String employeeType; + + private Long dateOfAppointment; + + @Valid + @NotEmpty + @Size(min = 1,max = 50) + private List jurisdictions = new ArrayList<>(); + + + @Valid + private List assignments = new ArrayList<>(); + + @Valid + @Size(max=25) + private List serviceHistory = new ArrayList<>(); + + + private Boolean IsActive; + + @Valid + @Size(max=25) + private List education = new ArrayList<>(); + + @Valid + @Size(max=25) + private List tests = new ArrayList<>(); + + @SafeHtml + @NotNull + @Size(max = 250) + private String tenantId; + + @Valid + @Size(max=50) + private List documents = new ArrayList<>(); + + @Valid + private List deactivationDetails = new ArrayList<>(); + + private List reactivationDetails = new ArrayList<>(); + + private AuditDetails auditDetails; + + private Boolean reActivateEmployee; + + @Valid + @NotNull + private User user; + + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/EmployeeDocument.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/EmployeeDocument.java new file mode 100644 index 00000000000..d93c69f4cf0 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/EmployeeDocument.java @@ -0,0 +1,85 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model; + +import org.egov.hrms.model.enums.EmployeeDocumentReferenceType; +import org.hibernate.validator.constraints.SafeHtml; +import org.springframework.validation.annotation.Validated; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Validated +@EqualsAndHashCode(exclude = {"auditDetails"}) +@AllArgsConstructor +@Getter +@NoArgsConstructor +@Setter +@ToString +@Builder +public class EmployeeDocument { + + @SafeHtml + private String id; + + @SafeHtml + private String documentName; + + @SafeHtml + private String documentId; + + private EmployeeDocumentReferenceType referenceType; + + @SafeHtml + private String referenceId; + + @SafeHtml + private String tenantId; + + private AuditDetails auditDetails; + + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Jurisdiction.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Jurisdiction.java new file mode 100644 index 00000000000..5afc27194cb --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Jurisdiction.java @@ -0,0 +1,86 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model; + +import lombok.*; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import org.hibernate.validator.constraints.SafeHtml; +import org.springframework.validation.annotation.Validated; + +@Validated +@EqualsAndHashCode(exclude = {"auditDetails"}) +@Builder +@AllArgsConstructor +@Getter +@NoArgsConstructor +@Setter +@ToString +public class Jurisdiction { + + @SafeHtml + private String id; + + @SafeHtml + @NotNull + @Size(min=2, max=100) + private String hierarchy; + + @SafeHtml + @NotNull + @Size(min=2, max=100) + private String boundary; + + @SafeHtml + @NotNull + @Size(max=256) + private String boundaryType; + + @SafeHtml + private String tenantId; + + private AuditDetails auditDetails; + + private Boolean isActive; + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/ReactivationDetails.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/ReactivationDetails.java new file mode 100644 index 00000000000..a5cb0c1a3c4 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/ReactivationDetails.java @@ -0,0 +1,45 @@ +package org.egov.hrms.model; + +import lombok.*; +import org.hibernate.validator.constraints.SafeHtml; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; + +@Validated +@EqualsAndHashCode(exclude = {"auditDetails"}) +@AllArgsConstructor +@Getter +@NoArgsConstructor +@Setter +@ToString +@Builder +public class ReactivationDetails { + + @SafeHtml + private String id; + + @SafeHtml + @NotNull + private String reasonForReactivation; + + @SafeHtml + private String orderNo; + + @SafeHtml + private String remarks; + + @NotNull + private Long effectiveFrom; + + @SafeHtml + private String tenantId; + + private AuditDetails auditDetails; + + + + +} + + diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Role.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Role.java new file mode 100644 index 00000000000..6ab3212b245 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Role.java @@ -0,0 +1,72 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model; + +import lombok.*; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Builder +@AllArgsConstructor +@EqualsAndHashCode +@Getter +@NoArgsConstructor +@Setter +@ToString +public class Role { + + + @NotNull + @Size(min=2, max=100) + private String name; + + @Size(min=2, max=100) + private String code; + + @Size(max=256) + private String description; + + @Size(max = 256) + private String tenantId; + + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/SMSRequest.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/SMSRequest.java new file mode 100644 index 00000000000..31c92e38ef7 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/SMSRequest.java @@ -0,0 +1,19 @@ +package org.egov.hrms.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + + +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString +public class SMSRequest { + private String mobileNumber; + private String message; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/ServiceHistory.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/ServiceHistory.java new file mode 100644 index 00000000000..56bdb6e2ca9 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/ServiceHistory.java @@ -0,0 +1,85 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model; + +import lombok.*; + +import javax.validation.constraints.NotNull; + +import org.hibernate.validator.constraints.SafeHtml; +import org.springframework.validation.annotation.Validated; + +@Validated +@EqualsAndHashCode(exclude = {"auditDetails"}) +@Builder +@AllArgsConstructor +@Getter +@NoArgsConstructor +@Setter +@ToString +public class ServiceHistory { + + @SafeHtml + private String id; + + @SafeHtml + private String serviceStatus; + + private Long serviceFrom; + + private Long serviceTo; + + @SafeHtml + private String orderNo; + + @SafeHtml + private String location; + + @SafeHtml + private String tenantId; + + private Boolean isCurrentPosition; + + private AuditDetails auditDetails; + + + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/DeactivationType.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/DeactivationType.java new file mode 100644 index 00000000000..3b632fc1e03 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/DeactivationType.java @@ -0,0 +1,31 @@ +package org.egov.hrms.model.enums; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + + +public enum DeactivationType { + SUSPENSION("SUSPENSION"), DEATH("DEATH"), RETIRED("RETIRED"); + + private String value; + + DeactivationType(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return name(); + } + + @JsonCreator + public static DeactivationType fromValue(String passedValue) { + for (DeactivationType obj : DeactivationType.values()) { + if (String.valueOf(obj.value).equals(passedValue.toUpperCase())) { + return obj; + } + } + return null; + } +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/EmployeeDocumentReferenceType.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/EmployeeDocumentReferenceType.java new file mode 100644 index 00000000000..f18fcd65a4d --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/EmployeeDocumentReferenceType.java @@ -0,0 +1,31 @@ +package org.egov.hrms.model.enums; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public enum EmployeeDocumentReferenceType { + HEADER("HEADER"), ASSIGNMENT("ASSIGNMENT"), JURISDICTION("JURISDICTION"), SERVICE("SERVICE"), + EDUCATION("EDUCATION"), TEST("TEST"), DEACTIVATION("DEACTIVATION"); + + private String value; + + EmployeeDocumentReferenceType(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return name(); + } + + @JsonCreator + public static EmployeeDocumentReferenceType fromValue(String passedValue) { + for (EmployeeDocumentReferenceType obj : EmployeeDocumentReferenceType.values()) { + if (String.valueOf(obj.value).equals(passedValue.toUpperCase())) { + return obj; + } + } + return null; + } +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/Gender.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/Gender.java new file mode 100644 index 00000000000..7ab9adf1c8d --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/Gender.java @@ -0,0 +1,70 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model.enums; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public enum Gender { + MALE("MALE"), FEMALE("FEMALE"), OTHERS("OTHERS"); + + private String value; + + Gender(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return name(); + } + + @JsonCreator + public static Gender fromValue(String passedValue) { + for (Gender obj : Gender.values()) { + if (String.valueOf(obj.value).equals(passedValue.toUpperCase())) { + return obj; + } + } + return null; + } +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/GuardianRelation.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/GuardianRelation.java new file mode 100644 index 00000000000..dead1f98b69 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/GuardianRelation.java @@ -0,0 +1,5 @@ +package org.egov.hrms.model.enums; + +public enum GuardianRelation { + FATHER, MOTHER, HUSBAND, OTHER; +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/UserType.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/UserType.java new file mode 100644 index 00000000000..153e5db53cd --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/UserType.java @@ -0,0 +1,70 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model.enums; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public enum UserType { + EMPLOYEE("EMPLOYEE"), CITIZEN("CITIZEN"), SYSTEM("SYSTEM"); + + private String value; + + UserType(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return name(); + } + + @JsonCreator + public static UserType fromValue(String passedValue) { + for (UserType obj : UserType.values()) { + if (String.valueOf(obj.value).equals(passedValue.toUpperCase())) { + return obj; + } + } + return null; + } +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/producer/HRMSProducer.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/producer/HRMSProducer.java new file mode 100644 index 00000000000..8521e631b1b --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/producer/HRMSProducer.java @@ -0,0 +1,19 @@ +package org.egov.hrms.producer; + +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.kafka.CustomKafkaTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class HRMSProducer { + + @Autowired + private CustomKafkaTemplate kafkaTemplate; + + public void push(String topic, Object value) { + log.info("Topic: "+topic); + kafkaTemplate.send(topic, value); + } +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeCountRowMapper.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeCountRowMapper.java new file mode 100644 index 00000000000..2266e24695f --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeCountRowMapper.java @@ -0,0 +1,58 @@ +package org.egov.hrms.repository; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.hrms.model.*; +import org.egov.hrms.model.enums.EmployeeDocumentReferenceType; +import org.egov.hrms.web.contract.User; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Component +@Slf4j +public class EmployeeCountRowMapper implements ResultSetExtractor> { + + @Autowired + private ObjectMapper mapper; + + @Override + /** + * Maps ResultSet to Employee POJO. + */ + public Map extractData(ResultSet rs) throws SQLException, DataAccessException { + Map response = new HashMap<>(); + int totalEmployee = 0; + int activeEmployee = 0; + int inactiveEmployee = 0; + while(rs.next()) { + if(rs.getBoolean("active")) + activeEmployee = activeEmployee + rs.getInt("count"); + else + inactiveEmployee = inactiveEmployee + rs.getInt("count"); + totalEmployee = totalEmployee + rs.getInt("count"); + } + if(totalEmployee==0){ + response.put("activeEmployee","0"); + response.put("inactiveEmployee", "0"); + } + response.put("activeEmployee", String.valueOf(activeEmployee)); + response.put("inactiveEmployee", String.valueOf(inactiveEmployee)); + response.put("totalEmployee", String.valueOf(totalEmployee)); + return response; + } + + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueries.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueries.java new file mode 100644 index 00000000000..6b824692a34 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueries.java @@ -0,0 +1,57 @@ +package org.egov.hrms.repository; + +import org.springframework.stereotype.Component; + +@Component +public class EmployeeQueries { + + public static final String HRMS_GET_EMPLOYEES = "SELECT employee.id as employee_id, employee.uuid as employee_uuid, employee.code as employee_code, " + + "employee.dateOfAppointment as employee_doa, employee.employeestatus as employee_status, employeetype as employee_type, employee.active as employee_active, employee.reactivateemployee as employee_reactive, " + + "employee.tenantid as employee_tenantid, employee.createdby as employee_createdby, employee.createddate as employee_createddate, " + + "employee.lastmodifiedby as employee_lastmodifiedby, employee.lastmodifieddate as employee_lastmodifieddate, assignment.uuid as assignment_uuid, " + + "assignment.position as assignment_position, assignment.department as assignment_department, assignment.designation as assignment_designation, " + + "assignment.fromdate as assignment_fromdate, assignment.todate as assignment_todate, assignment.govtordernumber as assignment_govtordernumber, " + + "assignment.reportingto as assignment_reportingto, assignment.ishod as assignment_ishod, assignment.iscurrentassignment as assignment_iscurrentassignment, " + + "assignment.tenantid as assignment_tenantid, " + + "assignment.createdby as assignment_createdby, assignment.createddate as assignment_createddate, assignment.lastmodifiedby as assignment_lastmodifiedby, " + + "assignment.lastmodifieddate as assignment_lastmodifieddate, education.uuid as education_uuid, education.qualification as education_qualification, " + + "education.stream as education_stream, education.yearofpassing as education_yearofpassing, education.university as education_university, " + + "education.remarks as education_remarks,education.isactive as education_isactive ,education.tenantid as education_tenantid, education.createdby as education_createdby, " + + "education.createddate as education_createddate, education.lastmodifiedby as education_lastmodifiedby, education.lastmodifieddate as education_lastmodifieddate, " + + "depttest.uuid as depttest_uuid, depttest.test as depttest_test, depttest.yearofpassing as depttest_yearofpassing, depttest.remarks as depttest_remarks, " + + "depttest.isactive as depttest_isactive, depttest.tenantid as depttest_tenantid, depttest.createdby as depttest_createdby, depttest.createddate as depttest_createddate, " + + "depttest.lastmodifiedby as depttest_lastmodifiedby, depttest.lastmodifieddate as depttest_lastmodifieddate, docs.uuid as docs_uuid, " + + "docs.documentid as docs_documentid, docs.documentname as docs_documentname, docs.referencetype as docs_referencetype, " + + "docs.referenceid as docs_referenceid, docs.tenantid as docs_tenantid, docs.createdby as docs_createdby, docs.createddate as docs_createddate, " + + "docs.lastmodifiedby as docs_lastmodifiedby, docs.lastmodifieddate as docs_lastmodifieddate, jurisdiction.uuid as jurisdiction_uuid, " + + "jurisdiction.hierarchy as jurisdiction_hierarchy, jurisdiction.boundarytype as jurisdiction_boundarytype, jurisdiction.boundary as jurisdiction_boundary, " + + "jurisdiction.isactive as jurisdiction_isactive, jurisdiction.tenantid as jurisdiction_tenantid, jurisdiction.createdby as jurisdiction_createdby, jurisdiction.createddate as jurisdiction_createddate, " + + "jurisdiction.lastmodifiedby as jurisdiction_lastmodifiedby, jurisdiction.lastmodifieddate as jurisdiction_lastmodifieddate, history.uuid as history_uuid, " + + "history.servicestatus as history_servicestatus, history.servicefrom as history_servicefrom, history.serviceto as history_serviceto, " + + "history.ordernumber as history_ordernumber, history.iscurrentposition as history_iscurrentposition, history.location as history_location, " + + "history.tenantid as history_tenantid, history.createdby as history_createdby, history.createddate as history_createddate, " + + "history.lastmodifiedby as history_lastmodifiedby, history.lastmodifieddate as history_lastmodifieddate, deact.uuid as deact_uuid, " + + "deact.reasonfordeactivation as deact_reasonfordeactivation, deact.effectivefrom as deact_effectivefrom, deact.ordernumber as deact_ordernumber, " + + "deact.remarks as deact_remarks, deact.tenantid as deact_tenantid, deact.createdby as deact_createdby, " + + "deact.createddate as deact_createddate, deact.lastmodifiedby as deact_lastmodifiedby, deact.lastmodifieddate as deact_lastmodifieddate, " + + "react.uuid as react_uuid, react.reasonforreactivation as react_reasonforreactivation, react.effectivefrom as react_effectivefrom, react.ordernumber as react_ordernumber, " + + "react.remarks as react_remarks, react.tenantid as react_tenantid, react.createdby as react_createdby, " + + "react.createddate as react_createddate, react.lastmodifiedby as react_lastmodifiedby, react.lastmodifieddate as react_lastmodifieddate " + + "FROM eg_hrms_employee employee LEFT JOIN eg_hrms_assignment assignment ON employee.uuid = assignment.employeeid LEFT JOIN eg_hrms_educationaldetails education " + + "ON employee.uuid = education.employeeid LEFT JOIN eg_hrms_departmentaltests depttest ON employee.uuid = depttest.employeeid LEFT JOIN eg_hrms_empdocuments docs " + + "ON employee.uuid = docs.employeeid LEFT JOIN eg_hrms_servicehistory history ON employee.uuid = history.employeeid LEFT JOIN eg_hrms_jurisdiction jurisdiction " + + "ON employee.uuid = jurisdiction.employeeid LEFT JOIN eg_hrms_deactivationdetails deact ON employee.uuid = deact.employeeid LEFT JOIN eg_hrms_reactivationdetails react " + + "ON employee.uuid = react.employeeid WHERE "; + + public static final String HRMS_PAGINATION_WRAPPER = "SELECT * FROM " + + "(SELECT *, DENSE_RANK() OVER (ORDER BY employee_uuid) offset_ FROM " + "({})" + " result) result_offset " + + "WHERE offset_ > $offset AND offset_ <= $limit"; + + public static final String HRMS_POSITION_SEQ = "SELECT NEXTVAL('EG_HRMS_POSITION')"; + + public static final String HRMS_GET_ASSIGNMENT = "select distinct(employeeid) from eg_hrms_assignment assignment where assignment.tenantid notnull "; + + public static final String HRMS_COUNT_EMP_QUERY = "SELECT active, count(*) FROM eg_hrms_employee WHERE tenantid "; + + public static final String HRMS_GET_UNASSIGNED_EMPLOYEES = "SELECT employee.uuid from eg_hrms_employee employee LEFT JOIN eg_hrms_assignment assignment ON employee.uuid = assignment.employeeid where assignment.employeeid is null"; +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueryBuilder.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueryBuilder.java new file mode 100644 index 00000000000..4e5e5d7bdc4 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueryBuilder.java @@ -0,0 +1,168 @@ +package org.egov.hrms.repository; + +import org.apache.commons.lang3.StringUtils; +import org.egov.hrms.config.PropertiesManager; +import org.egov.hrms.web.contract.EmployeeSearchCriteria; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +public class EmployeeQueryBuilder { + + @Value("${egov.hrms.default.pagination.limit}") + private Integer defaultLimit; + + @Autowired + private PropertiesManager properties; + + /** + * Returns query for searching employees + * + * @param criteria + * @return + */ + public String getEmployeeSearchQuery(EmployeeSearchCriteria criteria,List preparedStmtList ) { + StringBuilder builder = new StringBuilder(EmployeeQueries.HRMS_GET_EMPLOYEES); + addWhereClause(criteria, builder, preparedStmtList); + return paginationClause(criteria, builder); + } + + public String getEmployeeCountQuery(String tenantId, List preparedStmtList ) { + StringBuilder builder = new StringBuilder(EmployeeQueries.HRMS_COUNT_EMP_QUERY); + if(tenantId.equalsIgnoreCase(properties.stateLevelTenantId)){ + builder.append("LIKE ? "); + preparedStmtList.add(tenantId+"%"); + } + else{ + builder.append("= ? "); + preparedStmtList.add(tenantId); + } + builder.append("GROUP BY active"); + return builder.toString(); + } + + public String getPositionSeqQuery() { + return EmployeeQueries.HRMS_POSITION_SEQ; + } + + /** + * Adds where clause to the query based on the requirement. + * @param criteria + * @param builder + * @param preparedStmtList + */ + public void addWhereClause(EmployeeSearchCriteria criteria, StringBuilder builder, List preparedStmtList) { + if(!StringUtils.isEmpty(criteria.getTenantId())) { + builder.append(" employee.tenantid = ?"); + preparedStmtList.add(criteria.getTenantId()); + } + else + builder.append(" employee.tenantid NOTNULL"); + + if(!CollectionUtils.isEmpty(criteria.getCodes())){ + List codes = criteria.getCodes().stream().map(String::toLowerCase).collect(Collectors.toList()); + builder.append(" and lower(employee.code) IN (").append(createQuery(codes)).append(")"); + addToPreparedStatement(preparedStmtList, codes); + } + if(!CollectionUtils.isEmpty(criteria.getIds())){ + builder.append(" and employee.id IN (").append(createQuery(criteria.getIds())).append(")"); + addToPreparedStatement(preparedStmtList, criteria.getIds()); + } + if(!CollectionUtils.isEmpty(criteria.getUuids())){ + builder.append(" and employee.uuid IN (").append(createQuery(criteria.getUuids())).append(")"); + addToPreparedStatement(preparedStmtList, criteria.getUuids()); + } + if(!CollectionUtils.isEmpty(criteria.getEmployeestatuses())){ + builder.append(" and employee.employeestatus IN (").append(createQuery(criteria.getEmployeestatuses())).append(")"); + addToPreparedStatement(preparedStmtList, criteria.getEmployeestatuses()); + } + if(!CollectionUtils.isEmpty(criteria.getEmployeetypes())){ + builder.append(" and employee.employeetype IN (").append(createQuery(criteria.getEmployeetypes())).append(")"); + addToPreparedStatement(preparedStmtList, criteria.getEmployeetypes()); + } + if(criteria.getIsActive() != null){ + builder.append(" and employee.active = ?"); + preparedStmtList.add(criteria.getIsActive()); + } + } + + public String paginationClause(EmployeeSearchCriteria criteria, StringBuilder builder) { + String pagination = EmployeeQueries.HRMS_PAGINATION_WRAPPER; + pagination = pagination.replace("{}", builder.toString()); + if(null != criteria.getOffset()) + pagination = pagination.replace("$offset", criteria.getOffset().toString()); + else + pagination = pagination.replace("$offset", "0"); + + if(null != criteria.getLimit()){ + Integer limit = criteria.getLimit() + criteria.getOffset(); + pagination = pagination.replace("$limit", limit.toString()); + } + else + pagination = pagination.replace("$limit", defaultLimit.toString()); + + return pagination; + } + + public String getAssignmentSearchQuery(EmployeeSearchCriteria criteria, List preparedStmtList) { + StringBuilder builder = new StringBuilder(EmployeeQueries.HRMS_GET_ASSIGNMENT); + addWhereClauseAssignment(criteria, builder, preparedStmtList); + return builder.toString(); + } + + private void addWhereClauseAssignment(EmployeeSearchCriteria criteria, StringBuilder builder, List preparedStmtList) { + if(!CollectionUtils.isEmpty(criteria.getDepartments())){ + builder.append(" and assignment.department IN (").append(createQuery(criteria.getDepartments())).append(")"); + addToPreparedStatement(preparedStmtList, criteria.getDepartments()); + } + if(!CollectionUtils.isEmpty(criteria.getDesignations())){ + builder.append(" and assignment.designation IN (").append(createQuery(criteria.getDesignations())+")"); + addToPreparedStatement(preparedStmtList,criteria.getDesignations()); + } + if(!CollectionUtils.isEmpty(criteria.getPositions())){ + builder.append(" and assignment.position IN (").append(createQuery(criteria.getPositions())+")"); + addToPreparedStatement(preparedStmtList,criteria.getPositions()); + } + if(null != criteria.getAsOnDate()) { + builder.append( " and case when assignment.todate is null then assignment.fromdate <= ? else assignment.fromdate <= ? and assignment.todate > ? end"); + preparedStmtList.add(criteria.getAsOnDate()); + preparedStmtList.add(criteria.getAsOnDate()); + preparedStmtList.add(criteria.getAsOnDate()); + } + + + } + + + private String createQuery(List ids) { + StringBuilder builder = new StringBuilder(); + int length = ids.size(); + for (int i = 0; i < length; i++) { + builder.append(" ?"); + if (i != length - 1) + builder.append(","); + } + return builder.toString(); + } + + private void addToPreparedStatement(List preparedStmtList, List ids) { + ids.forEach(id -> { + preparedStmtList.add(id); + }); + } + + public String getUnassignedEmployeesSearchQuery(EmployeeSearchCriteria criteria, List preparedStmtList) { + StringBuilder builder = new StringBuilder(EmployeeQueries.HRMS_GET_UNASSIGNED_EMPLOYEES); + addWhereClauseAssignment(criteria, builder, preparedStmtList); + return builder.toString(); + } + + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeRepository.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeRepository.java new file mode 100644 index 00000000000..20bb37a813e --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeRepository.java @@ -0,0 +1,141 @@ +package org.egov.hrms.repository; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.common.contract.request.RequestInfo; +import org.egov.hrms.utils.HRMSUtils; +import org.egov.hrms.web.contract.EmployeeSearchCriteria; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import lombok.extern.slf4j.Slf4j; + +import org.egov.hrms.model.Employee; +import org.springframework.util.CollectionUtils; + +@Repository +@Slf4j +public class EmployeeRepository { + + @Autowired + private EmployeeQueryBuilder queryBuilder; + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Autowired + private EmployeeRowMapper rowMapper; + + @Autowired + private EmployeeCountRowMapper countRowMapper; + + @Autowired + private HRMSUtils hrmsUtils; + + /** + * DB Repository that makes jdbc calls to the db and fetches employees. + * + * @param criteria + * @param requestInfo + * @return + */ + public List fetchEmployees(EmployeeSearchCriteria criteria, RequestInfo requestInfo){ + List employees = new ArrayList<>(); + List preparedStmtList = new ArrayList<>(); + if(hrmsUtils.isAssignmentSearchReqd(criteria)) { + List empUuids = fetchEmployeesforAssignment(criteria, requestInfo); + if (CollectionUtils.isEmpty(empUuids)) + return employees; + else { + if(!CollectionUtils.isEmpty(criteria.getUuids())) + criteria.setUuids(criteria.getUuids().stream().filter(empUuids::contains).collect(Collectors.toList())); + else + criteria.setUuids(empUuids); + } + } + if (criteria.getIncludeUnassigned() != null && criteria.getIncludeUnassigned()) { + List empUuids = fetchUnassignedEmployees(criteria, requestInfo); + criteria.setUuids(empUuids); + } + String query = queryBuilder.getEmployeeSearchQuery(criteria, preparedStmtList); + try { + employees = jdbcTemplate.query(query, preparedStmtList.toArray(),rowMapper); + }catch(Exception e) { + log.error("Exception while making the db call: ",e); + log.error("query; "+query); + } + return employees; + } + + private List fetchUnassignedEmployees(EmployeeSearchCriteria criteria, RequestInfo requestInfo) { + List employeesIds = new ArrayList<>(); + List preparedStmtList = new ArrayList<>(); + String query = queryBuilder.getUnassignedEmployeesSearchQuery(criteria, preparedStmtList); + try { + employeesIds = jdbcTemplate.queryForList(query, preparedStmtList.toArray(),String.class); + }catch(Exception e) { + log.error("Exception while making the db call: ",e); + log.error("query; "+query); + } + return employeesIds; + } + + private List fetchEmployeesforAssignment(EmployeeSearchCriteria criteria, RequestInfo requestInfo) { + List employeesIds = new ArrayList<>(); + List preparedStmtList = new ArrayList<>(); + String query = queryBuilder.getAssignmentSearchQuery(criteria, preparedStmtList); + try { + + employeesIds = jdbcTemplate.queryForList(query, preparedStmtList.toArray(),String.class); + }catch(Exception e) { + log.error("Exception while making the db call: ",e); + log.error("query; "+query); + } + return employeesIds; + + } + + /** + * Fetches next value in the position seq table + * + * @return + */ + public Long fetchPosition(){ + String query = queryBuilder.getPositionSeqQuery(); + Long id = null; + try { + id = jdbcTemplate.queryForObject(query, Long.class); + }catch(Exception e) { + log.error("Exception while making the db call: ",e); + log.error("query; "+query); + } + return id; + } + + /** + * DB Repository that makes jdbc calls to the db and fetches employee count. + * + * @param tenantId + * @return + */ + public Map fetchEmployeeCount(String tenantId){ + Map response = new HashMap<>(); + List preparedStmtList = new ArrayList<>(); + + String query = queryBuilder.getEmployeeCountQuery(tenantId, preparedStmtList); + log.info("query; "+query); + try { + response=jdbcTemplate.query(query, preparedStmtList.toArray(),countRowMapper); + }catch(Exception e) { + log.error("Exception while making the db call: ",e); + log.error("query; "+query); + } + return response; + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeRowMapper.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeRowMapper.java new file mode 100644 index 00000000000..9d1ab4dd875 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeRowMapper.java @@ -0,0 +1,338 @@ +package org.egov.hrms.repository; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.hrms.model.*; +import org.egov.hrms.model.enums.EmployeeDocumentReferenceType; +import org.egov.hrms.web.contract.User; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Component +@Slf4j +public class EmployeeRowMapper implements ResultSetExtractor> { + + @Autowired + private ObjectMapper mapper; + + @Override + /** + * Maps ResultSet to Employee POJO. + */ + public List extractData(ResultSet rs) throws SQLException, DataAccessException { + Map employeeMap = new HashMap<>(); + while(rs.next()) { + String currentid = rs.getString("employee_uuid"); + Employee currentEmployee = employeeMap.get(currentid); + if(null == currentEmployee) { + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("employee_createdby")).createdDate(rs.getLong("employee_createddate")) + .lastModifiedBy(rs.getString("employee_lastmodifiedby")).lastModifiedDate(rs.getLong("employee_lastmodifieddate")).build(); + currentEmployee = Employee.builder().id(rs.getLong("employee_id")).uuid(rs.getString("employee_uuid")).tenantId(rs.getString("employee_tenantid")) + .code(rs.getString("employee_code")).dateOfAppointment(null == rs.getObject("employee_doa")? null : rs.getLong("employee_doa")).IsActive(rs.getBoolean("employee_active")) + .employeeStatus(rs.getString("employee_status")).employeeType(rs.getString("employee_type")).auditDetails(auditDetails).reActivateEmployee(rs.getBoolean("employee_reactive")) + .jurisdictions(new ArrayList()).assignments(new ArrayList()).user(new User()) + .build(); + } + addChildrenToEmployee(rs, currentEmployee); + employeeMap.put(currentid, currentEmployee); + } + + return new ArrayList<>(employeeMap.values()); + + } + + /** + * Adds all the children data to a employee object. + * + * @param rs + * @param currentEmployee + */ + public void addChildrenToEmployee(ResultSet rs, Employee currentEmployee) { + setAssignments(rs, currentEmployee); + setJurisdictions(rs, currentEmployee); + setEducationDetails(rs, currentEmployee); + setDeptTests(rs, currentEmployee); + setServiceHistory(rs, currentEmployee); + setDocuments(rs, currentEmployee); + setDeactivationDetails(rs, currentEmployee); + setReactivationDetails(rs, currentEmployee); + } + + /** + * Maps Assignments inside a ResultSet to the Assignment POJO inside employee object. + * + * @param rs + * @param currentEmployee + */ + public void setAssignments(ResultSet rs, Employee currentEmployee) { + try { + List assignments = new ArrayList<>(); + if(CollectionUtils.isEmpty(currentEmployee.getAssignments())) + assignments = new ArrayList(); + else + assignments = currentEmployee.getAssignments(); + + List ids = assignments.stream().map(Assignment::getId).collect(Collectors.toList()); + if(!StringUtils.isEmpty(rs.getString("assignment_uuid")) && !ids.contains(rs.getString("assignment_uuid"))) { + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("assignment_createdby")).createdDate(rs.getLong("assignment_createddate")) + .lastModifiedBy(rs.getString("assignment_lastmodifiedby")).lastModifiedDate(rs.getLong("assignment_lastmodifieddate")).build(); + + Assignment assignment = Assignment.builder().id(rs.getString("assignment_uuid")).position(rs.getLong("assignment_position")).department(rs.getString("assignment_department")) + .designation(rs.getString("assignment_designation")).fromDate(rs.getLong("assignment_fromdate")).toDate(null == rs.getObject("assignment_todate")? null : rs.getLong("assignment_todate")) + .govtOrderNumber(rs.getString("assignment_govtordernumber")).reportingTo(rs.getString("assignment_reportingto")).isHOD(rs.getBoolean("assignment_ishod")) + .isCurrentAssignment(rs.getBoolean("assignment_iscurrentassignment")).tenantid(rs.getString("assignment_tenantid")).auditDetails(auditDetails).build(); + + assignments.add(assignment); + } + currentEmployee.setAssignments(assignments); + }catch(Exception e) { + log.error("Error in row mapper while mapping Assignments: ",e); + throw new CustomException("ROWMAPPER_ERROR","Error in row mapper while mapping Assignments"); + } + } + + /** + * Maps Jurisdictions inside a ResultSet to the Jurisdiction POJO inside employee object. + * + * @param rs + * @param currentEmployee + */ + public void setJurisdictions(ResultSet rs, Employee currentEmployee) { + try { + List jurisdictions = new ArrayList<>(); + if(CollectionUtils.isEmpty(currentEmployee.getJurisdictions())) + jurisdictions = new ArrayList(); + else + jurisdictions = currentEmployee.getJurisdictions(); + + List ids = jurisdictions.stream().map(Jurisdiction::getId).collect(Collectors.toList()); + Boolean isActive = rs.getBoolean("jurisdiction_isactive") !=false; + if(isActive && !StringUtils.isEmpty(rs.getString("jurisdiction_uuid")) && !ids.contains(rs.getString("jurisdiction_uuid"))) { + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("jurisdiction_createdby")).createdDate(rs.getLong("jurisdiction_createddate")) + .lastModifiedBy(rs.getString("jurisdiction_lastmodifiedby")).lastModifiedDate(rs.getLong("jurisdiction_lastmodifieddate")).build(); + + Jurisdiction jurisdiction = Jurisdiction.builder().id(rs.getString("jurisdiction_uuid")).hierarchy(rs.getString("jurisdiction_hierarchy")) + .boundary(rs.getString("jurisdiction_boundary")).boundaryType(rs.getString("jurisdiction_boundarytype")) + .tenantId(rs.getString("jurisdiction_tenantid")) + .isActive(null == rs.getObject("jurisdiction_isactive")?true:rs.getBoolean("jurisdiction_isactive")) + .auditDetails(auditDetails).build(); + + jurisdictions.add(jurisdiction); + } + currentEmployee.setJurisdictions(jurisdictions); + }catch(Exception e) { + log.error("Error in row mapper while mapping Jurisdictions: ",e); + throw new CustomException("ROWMAPPER_ERROR","Error in row mapper while mapping Jurisdictions"); + } + } + + /** + * Maps EducationDetails inside a ResultSet to the EducationDetails POJO inside employee object. + * + * @param rs + * @param currentEmployee + */ + public void setEducationDetails(ResultSet rs, Employee currentEmployee) { + try { + List educationDetails = new ArrayList<>(); + if(CollectionUtils.isEmpty(currentEmployee.getEducation())) + educationDetails = new ArrayList(); + else + educationDetails = currentEmployee.getEducation(); + List ids = educationDetails.stream().map(EducationalQualification::getId).collect(Collectors.toList()); + Boolean isActive =rs.getBoolean("education_isactive") !=false; + if( isActive &&!StringUtils.isEmpty( rs.getString("education_uuid")) && !ids.contains(rs.getString("education_uuid"))) { + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("education_createdby")).createdDate(rs.getLong("education_createddate")) + .lastModifiedBy(rs.getString("education_lastmodifiedby")).lastModifiedDate(rs.getLong("education_lastmodifieddate")).build(); + EducationalQualification education = EducationalQualification.builder().id(rs.getString("education_uuid")).qualification(rs.getString("education_qualification")).stream(rs.getString("education_stream")) + .yearOfPassing(rs.getLong("education_yearofpassing")).university(rs.getString("education_university")).remarks(rs.getString("education_remarks")) + .tenantId(rs.getString("education_tenantid")) + .isActive(null == rs.getObject("education_isactive")?true:rs.getBoolean("education_isactive")) + .auditDetails(auditDetails).build(); + + educationDetails.add(education); + } + currentEmployee.setEducation(educationDetails); + }catch(Exception e) { + log.error("Error in row mapper while mapping Educational Details: ",e); + throw new CustomException("ROWMAPPER_ERROR","Error in row mapper while mapping Educational Details"); + } + } + + /** + * Maps Dept Tests inside a ResultSet to the DeptTest POJO inside employee object. + * + * @param rs + * @param currentEmployee + */ + public void setDeptTests(ResultSet rs, Employee currentEmployee) { + try { + List tests = new ArrayList<>(); + if(CollectionUtils.isEmpty(currentEmployee.getTests())) + tests = new ArrayList(); + else + tests = currentEmployee.getTests(); + + List ids = tests.stream().map(DepartmentalTest::getId).collect(Collectors.toList()); + Boolean isActive = rs.getBoolean("depttest_isactive") !=false; + if(isActive && !StringUtils.isEmpty(rs.getString("depttest_uuid")) && !ids.contains(rs.getString("depttest_uuid"))) { + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("depttest_createdby")).createdDate(rs.getLong("depttest_createddate")) + .lastModifiedBy(rs.getString("depttest_lastmodifiedby")).lastModifiedDate(rs.getLong("depttest_lastmodifieddate")).build(); + + DepartmentalTest test = DepartmentalTest.builder().id(rs.getString("depttest_uuid")).test(rs.getString("depttest_test")).yearOfPassing(rs.getLong("depttest_yearofpassing")) + .remarks(rs.getString("depttest_remarks")).tenantId(rs.getString("depttest_tenantid")) + .isActive(null == rs.getObject("depttest_isactive")?true:rs.getBoolean("depttest_isactive")) + .auditDetails(auditDetails).build(); + + tests.add(test); + } + currentEmployee.setTests(tests); + }catch(Exception e) { + log.error("Error in row mapper while mapping Departmental Tests: ",e); + throw new CustomException("ROWMAPPER_ERROR","Error in row mapper while mapping Departmental Tests"); + } + } + + /** + * Maps ServiceHistory inside a ResultSet to the ServiceHistory POJO inside employee object. + * + * @param rs + * @param currentEmployee + */ + public void setServiceHistory(ResultSet rs, Employee currentEmployee) { + try { + List history = new ArrayList<>(); + if(CollectionUtils.isEmpty(currentEmployee.getServiceHistory())) + history = new ArrayList(); + else + history = currentEmployee.getServiceHistory(); + + List ids = history.stream().map(ServiceHistory::getId).collect(Collectors.toList()); + if(!StringUtils.isEmpty(rs.getString("history_uuid")) && !ids.contains(rs.getString("history_uuid"))) { + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("history_createdby")).createdDate(rs.getLong("history_createddate")) + .lastModifiedBy(rs.getString("history_lastmodifiedby")).lastModifiedDate(rs.getLong("history_lastmodifieddate")).build(); + + ServiceHistory service = ServiceHistory.builder().id(rs.getString("history_uuid")).serviceStatus(rs.getString("history_servicestatus")).serviceFrom(rs.getLong("history_servicefrom")) + .serviceTo(null == rs.getObject("history_serviceto")? null :rs.getLong("history_serviceto")).orderNo(rs.getString("history_ordernumber")).isCurrentPosition(rs.getBoolean("history_iscurrentposition")) + .location(rs.getString("history_location")).tenantId(rs.getString("history_tenantid")).auditDetails(auditDetails).build(); + + history.add(service); + } + currentEmployee.setServiceHistory(history); + }catch(Exception e) { + log.error("Error in row mapper while mapping Service History: ",e); + throw new CustomException("ROWMAPPER_ERROR","Error in row mapper while mapping Service History"); + } + + } + + /** + * Maps Documents inside a ResultSet to the Document POJO inside employee object. + * + * @param rs + * @param currentEmployee + */ + public void setDocuments(ResultSet rs, Employee currentEmployee) { + try { + List documents = new ArrayList<>(); + if(CollectionUtils.isEmpty(currentEmployee.getDocuments())) + documents = new ArrayList(); + else + documents = currentEmployee.getDocuments(); + + List ids = documents.stream().map(EmployeeDocument::getId).collect(Collectors.toList()); + if(!StringUtils.isEmpty(rs.getString("docs_uuid")) && !ids.contains(rs.getString("docs_uuid")) ) { + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("docs_createdby")).createdDate(rs.getLong("docs_createddate")) + .lastModifiedBy(rs.getString("docs_lastmodifiedby")).lastModifiedDate(rs.getLong("docs_lastmodifieddate")).build(); + EmployeeDocument document = EmployeeDocument.builder().id(rs.getString("docs_uuid")).documentId(rs.getString("docs_documentid")) + .documentName(rs.getString("docs_documentname")).referenceType(rs.getString("docs_referencetype") != null ? EmployeeDocumentReferenceType.valueOf(rs.getString("docs_referencetype")): null) + .referenceId(rs.getString("docs_referenceid")).tenantId(rs.getString("docs_tenantid")).auditDetails(auditDetails).build(); + + documents.add(document); + } + currentEmployee.setDocuments(documents); + }catch(Exception e) { + log.error("Error in row mapper while mapping document: ",e); + throw new CustomException("ROWMAPPER_ERROR","Error in row mapper while mapping document"); + + } + } + + /** + * Maps DeactivationDetails inside a ResultSet to the DeactivationDetail POJO inside employee object. + * + * @param rs + * @param currentEmployee + */ + public void setDeactivationDetails(ResultSet rs, Employee currentEmployee) { + try { + List deactDetails = new ArrayList<>(); + if(CollectionUtils.isEmpty(currentEmployee.getDeactivationDetails())) + deactDetails = new ArrayList(); + else + deactDetails = currentEmployee.getDeactivationDetails(); + + List ids = deactDetails.stream().map(DeactivationDetails::getId).collect(Collectors.toList()); + if(!StringUtils.isEmpty(rs.getString("deact_uuid")) && !ids.contains(rs.getString("deact_uuid")) ) { + if(rs.getString("deact_uuid")!=null){ + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("deact_createdby")).createdDate(rs.getLong("deact_createddate")) + .lastModifiedBy(rs.getString("deact_lastmodifiedby")).lastModifiedDate(rs.getLong("deact_lastmodifieddate")).build(); + + DeactivationDetails deactDetail = DeactivationDetails.builder().id(rs.getString("deact_uuid")).reasonForDeactivation(rs.getString("deact_reasonfordeactivation")) + .effectiveFrom(rs.getLong("deact_effectivefrom")).orderNo(rs.getString("deact_ordernumber")).remarks(rs.getString("deact_remarks")!= null ? (rs.getString("deact_remarks")) : null) + .tenantId(rs.getString("deact_tenantid")).auditDetails(auditDetails).build(); + + deactDetails.add(deactDetail); + } + } + currentEmployee.setDeactivationDetails(deactDetails); + + }catch(Exception e) { + log.error("Error in row mapper while mapping deactivation details: ",e); + throw new CustomException("ROWMAPPER_ERROR","Error in row mapper while mapping deactivation details"); + } + } + + public void setReactivationDetails(ResultSet rs, Employee currentEmployee){ + try { + List reactDetails = new ArrayList<>(); + if(CollectionUtils.isEmpty(currentEmployee.getReactivationDetails())) + reactDetails = new ArrayList(); + else + reactDetails = currentEmployee.getReactivationDetails(); + + List ids = reactDetails.stream().map(ReactivationDetails::getId).collect(Collectors.toList()); + if(!StringUtils.isEmpty(rs.getString("react_uuid")) && !ids.contains(rs.getString("react_uuid")) ) { + if(rs.getString("react_uuid")!=null){ + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("react_createdby")).createdDate(rs.getLong("react_createddate")) + .lastModifiedBy(rs.getString("react_lastmodifiedby")).lastModifiedDate(rs.getLong("react_lastmodifieddate")).build(); + + ReactivationDetails reactDetail = ReactivationDetails.builder().id(rs.getString("react_uuid")).reasonForReactivation(rs.getString("react_reasonforreactivation")) + .effectiveFrom(rs.getLong("react_effectivefrom")).orderNo(rs.getString("react_ordernumber")).remarks(rs.getString("react_remarks")!= null ? (rs.getString("react_remarks")) : null) + .tenantId(rs.getString("react_tenantid")).auditDetails(auditDetails).build(); + + reactDetails.add(reactDetail); + } + } + currentEmployee.setReactivationDetails(reactDetails); + + }catch(Exception e) { + log.error("Error in row mapper while mapping reactivation details ",e); + throw new CustomException("ROWMAPPER_ERROR","Error in row mapper while mapping reactivation details"); + } + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/RestCallRepository.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/RestCallRepository.java new file mode 100644 index 00000000000..596538863e5 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/RestCallRepository.java @@ -0,0 +1,67 @@ +package org.egov.hrms.repository; + +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.egov.tracer.model.CustomException; +import org.egov.tracer.model.ServiceCallException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +import lombok.extern.slf4j.Slf4j; + +@Repository +@Slf4j +public class RestCallRepository { + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private ObjectMapper objectMapper; + + /** + * Fetches results from the given API and request and handles errors. + * + * @param requestInfo + * @param serviceReqSearchCriteria + * @return Object + * @author vishal + */ + public Object fetchResult(StringBuilder uri, Object request) { + Object response = null; + try { + response = restTemplate.postForObject(uri.toString(), request, Map.class); + } catch (HttpClientErrorException e) { + log.error("External Service threw an Exception: ", e); + if (!StringUtils.isEmpty(e.getResponseBodyAsString())) { + throw new ServiceCallException(e.getResponseBodyAsString()); + } + } catch (Exception e) { + log.error("Exception while fetching from searcher: ", e); + log.info("req: " + (request)); + } + + return response; + + } + + public T fetchResult(StringBuilder uri, Object request, Class + clazz) { + objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + T response; + try { + response = restTemplate.postForObject(uri.toString(), request, clazz); + } catch (HttpClientErrorException e) { + throw new CustomException("HTTP_CLIENT_ERROR", + String.format("%s - %s", e.getMessage(), e.getResponseBodyAsString())); + } + return response; + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/DefaultUserService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/DefaultUserService.java new file mode 100644 index 00000000000..0b232ae6448 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/DefaultUserService.java @@ -0,0 +1,281 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.request.Role; +import org.egov.common.contract.request.User; +import org.egov.common.utils.MultiStateInstanceUtil; +import org.egov.hrms.config.PropertiesManager; +import org.egov.hrms.repository.RestCallRepository; +import org.egov.hrms.utils.HRMSConstants; +import org.egov.hrms.web.contract.UserRequest; +import org.egov.hrms.web.contract.UserResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +import javax.annotation.PostConstruct; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; + +import static org.egov.hrms.utils.HRMSConstants.*; + +@Slf4j +@Setter +@Getter +public class DefaultUserService implements UserService { + + @Autowired + private PropertiesManager propertiesManager; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private RestCallRepository restCallRepository; + + @Autowired + private MultiStateInstanceUtil centralInstanceUtil; + + @Value("${egov.user.create.endpoint}") + private String userCreateEndpoint; + + @Value("${egov.user.search.endpoint}") + private String userSearchEndpoint; + + @Value("${egov.user.update.endpoint}") + private String userUpdateEndpoint; + + private String internalMicroserviceRoleUuid = null; + + @PostConstruct + void initalizeSystemuser(){ + log.info("initialising system user"); + RequestInfo requestInfo = new RequestInfo(); + StringBuilder uri = new StringBuilder(); + uri.append(propertiesManager.getUserHost()).append(propertiesManager.getUserSearchEndpoint()); // URL for user search call + Map userSearchRequest = new HashMap<>(); + userSearchRequest.put("RequestInfo", requestInfo); + userSearchRequest.put("tenantId", propertiesManager.getStateLevelTenantId()); + userSearchRequest.put("roleCodes", Collections.singletonList(INTERNALMICROSERVICEROLE_CODE)); + try { + LinkedHashMap responseMap = (LinkedHashMap) restCallRepository.fetchResult(uri, userSearchRequest); + List> users = (List>) responseMap.get("user"); + if(users.size()==0) + createInternalMicroserviceUser(requestInfo); + internalMicroserviceRoleUuid = (String) users.get(0).get("uuid"); + }catch (Exception e) { + throw new CustomException("EG_USER_SEARCH_ERROR", "Service returned null while fetching user"); + } + + } + + private void createInternalMicroserviceUser(RequestInfo requestInfo){ + Map userCreateRequest = new HashMap<>(); + //Creating role with INTERNAL_MICROSERVICE_ROLE + Role role = Role.builder() + .name(INTERNALMICROSERVICEROLE_NAME).code(INTERNALMICROSERVICEROLE_CODE) + .tenantId(propertiesManager.getStateLevelTenantId()).build(); + User user = User.builder().userName(INTERNALMICROSERVICEUSER_USERNAME) + .name(INTERNALMICROSERVICEUSER_NAME).mobileNumber(INTERNALMICROSERVICEUSER_MOBILENO) + .type(INTERNALMICROSERVICEUSER_TYPE).tenantId(propertiesManager.getStateLevelTenantId()) + .roles(Collections.singletonList(role)).id(0L).build(); + + userCreateRequest.put("RequestInfo", requestInfo); + userCreateRequest.put("user", user); + + StringBuilder uri = new StringBuilder(); + uri.append(propertiesManager.getUserHost()).append(propertiesManager.getUserCreateEndpoint()); // URL for user create call + + try { + LinkedHashMap responseMap = (LinkedHashMap) restCallRepository.fetchResult(uri, userCreateRequest); + List> users = (List>) responseMap.get("user"); + internalMicroserviceRoleUuid = (String) users.get(0).get("uuid"); + }catch (Exception e) { + throw new CustomException("EG_USER_CRETE_ERROR", "Service returned throws error while creating user"); + } + } + + @Override + public UserResponse createUser(UserRequest userRequest) { + StringBuilder uri = new StringBuilder(); + uri.append(propertiesManager.getUserHost()).append(propertiesManager.getUserCreateEndpoint()); + UserResponse userResponse = null; + try { + userResponse = userCall(userRequest,uri); + }catch(Exception e) { + log.error("User created failed: ",e); + } + + return userResponse; + } + + @Override + public UserResponse updateUser(UserRequest userRequest) { + StringBuilder uri = new StringBuilder(); + uri.append(propertiesManager.getUserHost()).append(propertiesManager.getUserUpdateEndpoint()); + UserResponse userResponse = null; + try { + userResponse = userCall(userRequest,uri); + }catch(Exception e) { + log.error("User created failed: ",e); + } + + return userResponse; + } + + @Override + public UserResponse getUser(RequestInfo requestInfo, Map userSearchCriteria) { + StringBuilder uri = new StringBuilder(); + Map userSearchReq = new HashMap<>(); + User userInfoCopy = requestInfo.getUserInfo(); + + if(propertiesManager.getIsDecryptionEnable()){ + User enrichedUserInfo = getEncrichedandCopiedUserInfo(String.valueOf(userSearchCriteria.get("tenantId"))); + requestInfo.setUserInfo(enrichedUserInfo); + } + + userSearchReq.put("RequestInfo", requestInfo); + userSearchReq.put(HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE,HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE); + for( String key: userSearchCriteria.keySet()) + userSearchReq.put(key, userSearchCriteria.get(key)); + uri.append(propertiesManager.getUserHost()).append(propertiesManager.getUserSearchEndpoint()); + UserResponse userResponse = new UserResponse(); + try { + userResponse = userCall(userSearchReq,uri); + }catch(Exception e) { + log.error("User search failed: ",e); + } + if(propertiesManager.getIsDecryptionEnable()) + requestInfo.setUserInfo(userInfoCopy); + + return userResponse; + } + + private User getEncrichedandCopiedUserInfo(String tenantId){ + //Creating role with INTERNAL_MICROSERVICE_ROLE + Role role = Role.builder() + .name(INTERNALMICROSERVICEROLE_NAME).code(INTERNALMICROSERVICEROLE_CODE) + .tenantId(centralInstanceUtil.getStateLevelTenant(tenantId)).build(); + + //Creating userinfo with uuid and role of internal micro service role + User userInfo = User.builder() + .uuid(internalMicroserviceRoleUuid) + .type(INTERNALMICROSERVICEUSER_TYPE) + .roles(Collections.singletonList(role)).id(0L).build(); + + return userInfo; + } + + + /** + * Returns UserDetailResponse by calling user service with given uri and object + * @param userRequest Request object for user service + * @param uri The address of the endpoint + * @return Response from user service as parsed as userDetailResponse + */ + @SuppressWarnings("all") + private UserResponse userCall(Object userRequest, StringBuilder uri) { + String dobFormat = null; + if(uri.toString().contains(userSearchEndpoint) || uri.toString().contains(userUpdateEndpoint)) + dobFormat="yyyy-MM-dd"; + else if(uri.toString().contains(userCreateEndpoint)) + dobFormat = "dd/MM/yyyy"; + try{ + LinkedHashMap responseMap = (LinkedHashMap) restCallRepository.fetchResult(uri, userRequest); + parseResponse(responseMap,dobFormat); + UserResponse userDetailResponse = objectMapper.convertValue(responseMap,UserResponse.class); + return userDetailResponse; + } + catch(IllegalArgumentException e) { + throw new CustomException("IllegalArgumentException","ObjectMapper not able to convertValue in userCall"); + } + } + + + /** + * Parses date formats to long for all users in responseMap + * @param responeMap LinkedHashMap got from user api response + * @param dobFormat dob format (required because dob is returned in different format's in search and create response in user service) + */ + @SuppressWarnings("all") + private void parseResponse(LinkedHashMap responeMap,String dobFormat){ + List users = (List)responeMap.get("user"); + String format1 = "dd-MM-yyyy HH:mm:ss"; + if(users!=null){ + users.forEach( map -> { + map.put("createdDate",dateTolong((String)map.get("createdDate"),format1)); + if((String)map.get("lastModifiedDate")!=null) + map.put("lastModifiedDate",dateTolong((String)map.get("lastModifiedDate"),format1)); + if((String)map.get("dob")!=null) + map.put("dob",dateTolong((String)map.get("dob"),dobFormat)); + if((String)map.get("pwdExpiryDate")!=null) + map.put("pwdExpiryDate",dateTolong((String)map.get("pwdExpiryDate"),format1)); + } + ); + } + } + + /** + * Converts date to long + * @param date date to be parsed + * @param format Format of the date + * @return Long value of date + */ + private Long dateTolong(String date,String format){ + SimpleDateFormat f = new SimpleDateFormat(format); + Date d = null; + try { + d = f.parse(date); + } catch (ParseException e) { + e.printStackTrace(); + } + return d.getTime(); + } + + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java new file mode 100644 index 00000000000..2cecd5f5f71 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java @@ -0,0 +1,618 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.hrms.config.PropertiesManager; +import org.egov.hrms.model.AuditDetails; +import org.egov.hrms.model.Employee; +import org.egov.hrms.model.enums.UserType; +import org.egov.hrms.producer.HRMSProducer; +import org.egov.hrms.repository.EmployeeRepository; +import org.egov.hrms.utils.ErrorConstants; +import org.egov.hrms.utils.HRMSConstants; +import org.egov.hrms.utils.HRMSUtils; +import org.egov.hrms.utils.ResponseInfoFactory; +import org.egov.hrms.web.contract.*; +import org.egov.tracer.kafka.LogAwareKafkaTemplate; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Data +@Slf4j +@Service +public class EmployeeService { + + + @Autowired + private UserService userService; + + @Autowired + private IdGenService idGenService; + + @Autowired + private ResponseInfoFactory factory; + + @Autowired + private LogAwareKafkaTemplate kafkaTemplate; + + @Autowired + private PropertiesManager propertiesManager; + + @Autowired + private HRMSProducer hrmsProducer; + + @Autowired + private EmployeeRepository repository; + + @Autowired + private HRMSUtils hrmsUtils; + + @Autowired + private NotificationService notificationService; + + @Autowired + private ObjectMapper objectMapper; + + /** + * Service method for create employee. Does following: + * 1. Sets ids to all the objects using idgen service. + * 2. Enriches the employee object with required parameters + * 3. Creates user in the egov-user service. + * 4. Sends notification upon successful creation + * + * @param employeeRequest + * @return + */ + public EmployeeResponse create(EmployeeRequest employeeRequest) { + RequestInfo requestInfo = employeeRequest.getRequestInfo(); + Map pwdMap = new HashMap<>(); + idGenService.setIds(employeeRequest); + employeeRequest.getEmployees().stream().forEach(employee -> { + enrichCreateRequest(employee, requestInfo); + createUser(employee, requestInfo); + pwdMap.put(employee.getUuid(), employee.getUser().getPassword()); + employee.getUser().setPassword(null); + }); + hrmsProducer.push(propertiesManager.getSaveEmployeeTopic(), employeeRequest); + notificationService.sendNotification(employeeRequest, pwdMap); + return generateResponse(employeeRequest); + } + + /** + * Searches employees on a given criteria. + * + * @param criteria + * @param requestInfo + * @return + */ + public EmployeeResponse search(EmployeeSearchCriteria criteria, RequestInfo requestInfo) { + boolean userChecked = false; + /*if(null == criteria.getIsActive() || criteria.getIsActive()) + criteria.setIsActive(true); + else + criteria.setIsActive(false);*/ + Map mapOfUsers = new HashMap(); + if(!StringUtils.isEmpty(criteria.getPhone()) + || !CollectionUtils.isEmpty(criteria.getRoles()) + || !CollectionUtils.isEmpty(criteria.getCodes())) { + Map userSearchCriteria = new HashMap<>(); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE, HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID,criteria.getTenantId()); + if(!StringUtils.isEmpty(criteria.getPhone())) + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_MOBILENO,criteria.getPhone()); + if( !CollectionUtils.isEmpty(criteria.getRoles()) ) + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_ROLECODES,criteria.getRoles()); + if (!CollectionUtils.isEmpty(criteria.getCodes())) { + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_USERNAME, criteria.getCodes().get(0)); + } + UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + userChecked =true; + if(!CollectionUtils.isEmpty(userResponse.getUser())) { + mapOfUsers.putAll(userResponse.getUser().stream() + .collect(Collectors.toMap(User::getUuid, Function.identity()))); + } + List userUUIDs = userResponse.getUser().stream().map(User :: getUuid).collect(Collectors.toList()); + if(!CollectionUtils.isEmpty(criteria.getUuids())) + criteria.setUuids(criteria.getUuids().stream().filter(userUUIDs::contains).collect(Collectors.toList())); + else + criteria.setUuids(userUUIDs); + } + //checks if above criteria met and result is not null will check for name search if list of names are given as user search on name is not bulk api + + if(!((!CollectionUtils.isEmpty(criteria.getRoles()) || !StringUtils.isEmpty(criteria.getPhone())) && CollectionUtils.isEmpty(criteria.getUuids()))){ + if(!CollectionUtils.isEmpty(criteria.getNames())) { + List userUUIDs = new ArrayList<>(); + for(String name: criteria.getNames()) { + Map userSearchCriteria = new HashMap<>(); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE, HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID,criteria.getTenantId()); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_NAME,name); + UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + userChecked =true; + if(!CollectionUtils.isEmpty(userResponse.getUser())) { + mapOfUsers.putAll(userResponse.getUser().stream() + .collect(Collectors.toMap(User::getUuid, Function.identity()))); + } + List uuids = userResponse.getUser().stream().map(User :: getUuid).collect(Collectors.toList()); + userUUIDs.addAll(uuids); + } + if(!CollectionUtils.isEmpty(criteria.getUuids())) + criteria.setUuids(criteria.getUuids().stream().filter(userUUIDs::contains).collect(Collectors.toList())); + else + criteria.setUuids(userUUIDs); + } + } + if(userChecked) + criteria.setTenantId(null); + List employees = new ArrayList<>(); + if(!((!CollectionUtils.isEmpty(criteria.getRoles()) || !CollectionUtils.isEmpty(criteria.getNames()) || !StringUtils.isEmpty(criteria.getPhone())) && CollectionUtils.isEmpty(criteria.getUuids()))) + employees = repository.fetchEmployees(criteria, requestInfo); + List uuids = employees.stream().map(Employee :: getUuid).collect(Collectors.toList()); + if(!CollectionUtils.isEmpty(uuids)){ + Map userSearchCriteria = new HashMap<>(); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE, HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_UUID,uuids); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID, criteria.getTenantId()); + log.info("uuid is available {}", userSearchCriteria); + if(mapOfUsers.isEmpty()){ + log.info("searching in user service"); + UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + if(!CollectionUtils.isEmpty(userResponse.getUser())) { + mapOfUsers = userResponse.getUser().stream() + .collect(Collectors.toMap(User :: getUuid, Function.identity())); + } + } + for(Employee employee: employees){ + employee.setUser(mapOfUsers.get(employee.getUuid())); + } + } + return EmployeeResponse.builder().responseInfo(factory.createResponseInfoFromRequestInfo(requestInfo, true)) + .employees(employees).build(); + } + + + /** + * Creates user by making call to egov-user. + * + * @param employee + * @param requestInfo + */ + private void createUser(Employee employee, RequestInfo requestInfo) { + enrichUser(employee); + UserRequest request = UserRequest.builder().requestInfo(requestInfo).user(employee.getUser()).build(); + try { + UserResponse response = userService.createUser(request); + User user = response.getUser().get(0); + employee.setId(UUID.fromString(user.getUuid()).getMostSignificantBits()); + employee.setUuid(user.getUuid()); + employee.getUser().setId(user.getId()); + employee.getUser().setUuid(user.getUuid()); + employee.getUser().setUserServiceUuid(user.getUserServiceUuid()); + }catch(Exception e) { + log.error("Exception while creating user: ",e); + log.error("request: "+request); + throw new CustomException(ErrorConstants.HRMS_USER_CREATION_FAILED_CODE, ErrorConstants.HRMS_USER_CREATION_FAILED_MSG); + } + + } + + /** + * Enriches the user object. + * + * @param employee + */ + private void enrichUser(Employee employee) { + List pwdParams = new ArrayList<>(); + pwdParams.add(employee.getCode()); + pwdParams.add(employee.getUser().getMobileNumber()); + pwdParams.add(employee.getTenantId()); + pwdParams.add(employee.getUser().getName().toUpperCase()); + if (propertiesManager.isAutoGeneratePassword()) { + employee.getUser().setPassword(hrmsUtils.generatePassword(pwdParams)); + } + employee.getUser().setUserName(employee.getCode()); + employee.getUser().setActive(true); + employee.getUser().setType(UserType.EMPLOYEE.toString()); + } + + /** + * Enriches employee object by setting parent ids to all the child objects + * + * @param employee + * @param requestInfo + */ + private void enrichCreateRequest(Employee employee, RequestInfo requestInfo) { + + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(requestInfo.getUserInfo().getUuid()) + .createdDate(new Date().getTime()) + .build(); + + employee.getJurisdictions().stream().forEach(jurisdiction -> { + jurisdiction.setId(UUID.randomUUID().toString()); + jurisdiction.setAuditDetails(auditDetails); + if(null == jurisdiction.getIsActive()) + jurisdiction.setIsActive(true); + }); + if (employee.getAssignments() != null && !employee.getAssignments().isEmpty()) { + employee.getAssignments().stream().forEach(assignment -> { + assignment.setId(UUID.randomUUID().toString()); + assignment.setAuditDetails(auditDetails); + assignment.setPosition(getPosition()); + }); + } + if(!CollectionUtils.isEmpty(employee.getServiceHistory())) { + employee.getServiceHistory().stream().forEach(serviceHistory -> { + serviceHistory.setId(UUID.randomUUID().toString()); + serviceHistory.setAuditDetails(auditDetails); + if(null == serviceHistory.getIsCurrentPosition()) + serviceHistory.setIsCurrentPosition(false); + }); + } + if(!CollectionUtils.isEmpty(employee.getEducation())) { + employee.getEducation().stream().forEach(educationalQualification -> { + educationalQualification.setId(UUID.randomUUID().toString()); + educationalQualification.setAuditDetails(auditDetails); + if(null == educationalQualification.getIsActive()) + educationalQualification.setIsActive(true); + }); + } + if(!CollectionUtils.isEmpty(employee.getTests())) { + employee.getTests().stream().forEach(departmentalTest -> { + departmentalTest.setId(UUID.randomUUID().toString()); + departmentalTest.setAuditDetails(auditDetails); + if(null == departmentalTest.getIsActive()) + departmentalTest.setIsActive(true); + }); + } + if(!CollectionUtils.isEmpty(employee.getDocuments())) { + employee.getDocuments().stream().forEach(document -> { + document.setId(UUID.randomUUID().toString()); + document.setAuditDetails(auditDetails); + }); + } + employee.setAuditDetails(auditDetails); + employee.setIsActive(true); + } + + /** + * Fetches next value from the position sequence table + * @return + */ + public Long getPosition() { + return repository.fetchPosition(); + } + + /** + * Updates the details of employees provided in the EmployeeRequest. + * TODO FIXME + * This method searches and updates the USER, INDIVIDUAL manually + * instead of cascading the update call directly to other services, + * the flow has to be relooked + * + * @param employeeRequest + * @return + */ + public EmployeeResponse update(EmployeeRequest employeeRequest) { + // Extracting request information from the employee request + RequestInfo requestInfo = employeeRequest.getRequestInfo(); + + // Initialize tenantId to null + String tenantId = null; + + // If employeeRequest is not null and contains employees, extract the tenantId from the first employee + if (employeeRequest != null && !CollectionUtils.isEmpty(employeeRequest.getEmployees()) && !employeeRequest.getEmployees().isEmpty()) { + tenantId = employeeRequest.getEmployees().get(0).getTenantId(); + } + + // List to store the UUIDs of the employees to be updated + List uuidList = new ArrayList<>(); + + // Iterate over the employees in the request and collect their UUIDs + for (Employee employee : employeeRequest.getEmployees()) { + uuidList.add(employee.getUuid()); + } + + // Search for existing employees based on the collected UUIDs and tenantId + EmployeeResponse existingEmployeeResponse = search( + EmployeeSearchCriteria.builder().uuids(uuidList).tenantId(tenantId).build(), requestInfo + ); + + // Extract the list of existing employees from the search response + List existingEmployees = existingEmployeeResponse.getEmployees(); + + // Iterate over each employee in the request + employeeRequest.getEmployees().stream().forEach(employee -> { + // Enrich the update request with additional information using the existing employee details + enrichUpdateRequest(employee, requestInfo, existingEmployees); + // Update the user information for the employee + updateUser(employee, requestInfo); + }); + + // Push the updated employee request to the HRMS topic for further processing + hrmsProducer.push(propertiesManager.getUpdateTopic(), employeeRequest); + + // (Optional) Send reactivation notifications if needed + // notificationService.sendReactivationNotification(employeeRequest); + + // Generate and return the response containing the updated employee information + return generateResponse(employeeRequest); + } + + /** + * Updates the user by making call to the user service. + * + * @param employee + * @param requestInfo + */ + private void updateUser(Employee employee, RequestInfo requestInfo) { + UserRequest request = UserRequest.builder().requestInfo(requestInfo).user(employee.getUser()).build(); + try { + userService.updateUser(request); + }catch(Exception e) { + log.error("Exception while updating user: ",e); + log.error("request: "+request); + throw new CustomException(ErrorConstants.HRMS_USER_UPDATION_FAILED_CODE, ErrorConstants.HRMS_USER_UPDATION_FAILED_MSG); + } + + } + + /** + * Enriches update request with required parameters. + * + * @param employee + * @param requestInfo + * @param existingEmployeesData + */ + private void enrichUpdateRequest(Employee employee, RequestInfo requestInfo, List existingEmployeesData) { + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(requestInfo.getUserInfo().getUserName()) + .createdDate(new Date().getTime()) + .build(); + // Find the existing employee data matching the current employee's UUID + Employee existingEmpData = existingEmployeesData.stream() + .filter(existingEmployee -> existingEmployee.getUuid().equals(employee.getUuid())) + .findFirst() + .orElseThrow(() -> new CustomException("EMPLOYEE_NOT_FOUND", "Employee not found with UUID: " + employee.getUuid())); + + // Set the user's username to the employee's code + employee.getUser().setUserName(employee.getCode()); + + // Set the user's active status based on the employee's isActive status + if(!employee.getIsActive()) + employee.getUser().setActive(false); + else + employee.getUser().setActive(true); + + employee.getJurisdictions().stream().forEach(jurisdiction -> { + + if(null == jurisdiction.getIsActive()) + jurisdiction.setIsActive(true); + if(jurisdiction.getId()==null) { + jurisdiction.setId(UUID.randomUUID().toString()); + jurisdiction.setAuditDetails(auditDetails); + }else{ + if(!existingEmpData.getJurisdictions().stream() + .filter(jurisdictionData ->jurisdictionData.getId().equals(jurisdiction.getId() )) + .findFirst().orElse(null) + .equals(jurisdiction)){ + jurisdiction.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUserName()); + jurisdiction.getAuditDetails().setLastModifiedDate(new Date().getTime()); + } + } + }); + employee.getAssignments().stream().forEach(assignment -> { + if(assignment.getId()==null) { + assignment.setId(UUID.randomUUID().toString()); + assignment.setAuditDetails(auditDetails); + }else { + if(!existingEmpData.getAssignments().stream() + .filter(assignmentData -> assignmentData.getId().equals(assignment.getId())) + .findFirst().orElse(null) + .equals(assignment)){ + assignment.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUserName()); + assignment.getAuditDetails().setLastModifiedDate(new Date().getTime()); + } + } + }); + + if(employee.getServiceHistory()!=null){ + employee.getServiceHistory().stream().forEach(serviceHistory -> { + if(null == serviceHistory.getIsCurrentPosition()) + serviceHistory.setIsCurrentPosition(false); + if(serviceHistory.getId()==null) { + serviceHistory.setId(UUID.randomUUID().toString()); + serviceHistory.setAuditDetails(auditDetails); + }else { + if(!existingEmpData.getServiceHistory().stream() + .filter(serviceHistoryData -> serviceHistoryData.getId().equals(serviceHistory.getId())) + .findFirst().orElse(null) + .equals(serviceHistory)){ + serviceHistory.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUserName()); + serviceHistory.getAuditDetails().setLastModifiedDate(new Date().getTime()); + } + } + }); + + } + + if(employee.getEducation() != null){ + employee.getEducation().stream().forEach(educationalQualification -> { + if(null == educationalQualification.getIsActive()) + educationalQualification.setIsActive(true); + if(educationalQualification.getId()==null) { + educationalQualification.setId(UUID.randomUUID().toString()); + educationalQualification.setAuditDetails(auditDetails); + }else { + + if(!existingEmpData.getEducation().stream() + .filter(educationalQualificationData -> educationalQualificationData.getId().equals(educationalQualification.getId())) + .findFirst().orElse(null) + .equals(educationalQualification)){ + educationalQualification.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUserName()); + educationalQualification.getAuditDetails().setLastModifiedDate(new Date().getTime()); + } + } + }); + + } + + if(employee.getTests() != null){ + employee.getTests().stream().forEach(departmentalTest -> { + + if(null == departmentalTest.getIsActive()) + departmentalTest.setIsActive(true); + if(departmentalTest.getId()==null) { + departmentalTest.setId(UUID.randomUUID().toString()); + departmentalTest.setAuditDetails(auditDetails); + }else { + if(!existingEmpData.getTests().stream() + .filter(departmentalTestData -> departmentalTestData.getId().equals(departmentalTest.getId())) + .findFirst().orElse(null) + .equals(departmentalTest)){ + departmentalTest.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUserName()); + departmentalTest.getAuditDetails().setLastModifiedDate(new Date().getTime()); + } + } + }); + + } + + if(employee.getDocuments() != null){ + employee.getDocuments().stream().forEach(document -> { + if(document.getId()==null) { + document.setId(UUID.randomUUID().toString()); + document.setAuditDetails(auditDetails); + }else { + if(!existingEmpData.getDocuments().stream() + .filter(documentData -> documentData.getId().equals(document.getId())) + .findFirst().orElse(null) + .equals(document)){ + document.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUserName()); + document.getAuditDetails().setLastModifiedDate(new Date().getTime()); + } + } + }); + + } + + if(employee.getDeactivationDetails() != null){ + employee.getDeactivationDetails().stream().forEach(deactivationDetails -> { + if(deactivationDetails.getId()==null) { + deactivationDetails.setId(UUID.randomUUID().toString()); + deactivationDetails.setAuditDetails(auditDetails); + employee.getDocuments().forEach(employeeDocument -> { + employeeDocument.setReferenceId( deactivationDetails.getId()); + }); + }else { + if(!existingEmpData.getDeactivationDetails().stream() + .filter(deactivationDetailsData -> deactivationDetailsData.getId().equals(deactivationDetails.getId())) + .findFirst().orElse(null) + .equals(deactivationDetails)){ + deactivationDetails.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUserName()); + deactivationDetails.getAuditDetails().setLastModifiedDate(new Date().getTime()); + } + } + }); + + } + if(employee.getReactivationDetails() != null){ + employee.getReactivationDetails().stream().forEach(reactivationDetails -> { + if(reactivationDetails.getId() == null){ + reactivationDetails.setId(UUID.randomUUID().toString()); + reactivationDetails.setAuditDetails(auditDetails); + employee.getDocuments().forEach(employeeDocument -> { + employeeDocument.setReferenceId(reactivationDetails.getId()); + }); + } + else{ + if(!existingEmpData.getReactivationDetails().stream() + .filter(reactivationDetails1 -> reactivationDetails1.getId().equals(reactivationDetails.getId())) + .findFirst().orElse(null) + .equals(reactivationDetails)){ + reactivationDetails.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUserName()); + reactivationDetails.getAuditDetails().setLastModifiedDate(new Date().getTime()); + } + } + }); + + } + + + } + + private EmployeeResponse generateResponse(EmployeeRequest employeeRequest) { + return EmployeeResponse.builder() + .responseInfo(factory.createResponseInfoFromRequestInfo(employeeRequest.getRequestInfo(), true)) + .employees(employeeRequest.getEmployees()).build(); + } + + public Map getEmployeeCountResponse(RequestInfo requestInfo, String tenantId){ + Map response = new HashMap<>(); + Map results = new HashMap<>(); + ResponseInfo responseInfo = factory.createResponseInfoFromRequestInfo(requestInfo, true); + + response.put("ResponseInfo",responseInfo); + results = repository.fetchEmployeeCount(tenantId); + + if(CollectionUtils.isEmpty(results) || results.get("totalEmployee").equalsIgnoreCase("0")){ + Map error = new HashMap<>(); + error.put("NO_RECORDS","No records found for the tenantId: "+tenantId); + throw new CustomException(error); + } + + response.put("EmployeCount",results); + return response; + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IdGenService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IdGenService.java new file mode 100644 index 00000000000..4e6420247ce --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IdGenService.java @@ -0,0 +1,90 @@ +package org.egov.hrms.service; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collector; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.hrms.config.PropertiesManager; +import org.egov.hrms.model.Employee; +import org.egov.hrms.repository.RestCallRepository; +import org.egov.hrms.utils.ErrorConstants; +import org.egov.hrms.web.contract.EmployeeRequest; +import org.egov.hrms.web.contract.IdGenerationRequest; +import org.egov.hrms.web.contract.IdGenerationResponse; +import org.egov.hrms.web.contract.IdRequest; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class IdGenService { + + @Autowired + private RestCallRepository repository; + + @Autowired + private PropertiesManager properties; + + /** + * Sets ids to all the employee objects + * + * @param employeeRequest + */ + public void setIds(EmployeeRequest employeeRequest) { + String tenantId = employeeRequest.getEmployees().get(0).getTenantId(); + Integer employeesWithCode = employeeRequest.getEmployees().stream() + .filter(employee -> !StringUtils.isEmpty(employee.getCode())).collect(Collectors.toList()).size(); + if(employeesWithCode == employeeRequest.getEmployees().size()) + return; + IdGenerationResponse response = getId(employeeRequest.getRequestInfo(), tenantId, employeeRequest.getEmployees().size() - employeesWithCode, + properties.getHrmsIdGenKey(), properties.getHrmsIdGenFormat()); + if(null != response) { + int i = 0; + for(Employee employee: employeeRequest.getEmployees()) { + if(StringUtils.isEmpty(employee.getCode())) { + employee.setCode(response.getIdResponses().get(i).getId()); + i++; + } + } + } + } + + /** + * Makes call to the idgen service to fetch ids for the employee object. Format of the id configurable. + * + * @param requestInfo + * @param tenantId + * @param count + * @param name + * @param format + * @return + */ + public IdGenerationResponse getId(RequestInfo requestInfo, String tenantId, Integer count, String name, String format) { + StringBuilder uri = new StringBuilder(); + ObjectMapper mapper = new ObjectMapper(); + uri.append(properties.getIdGenHost()).append(properties.getIdGenEndpoint()); + List reqList = new ArrayList<>(); + for (int i = 0; i < count; i++) { + reqList.add(IdRequest.builder().idName(name).format(format).tenantId(tenantId).build()); + } + IdGenerationRequest request = IdGenerationRequest.builder().idRequests(reqList).requestInfo(requestInfo).build(); + IdGenerationResponse response = null; + try { + response = mapper.convertValue(repository.fetchResult(uri, request), IdGenerationResponse.class); + }catch(Exception e) { + log.error("Exception while generating ids: ",e); + log.error("Request: "+request); + throw new CustomException(ErrorConstants.HRMS_GENERATE_ID_ERROR_CODE,ErrorConstants.HRMS_GENERATE_ID_ERROR_MSG); + + } + return response; + } +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IndividualService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IndividualService.java new file mode 100644 index 00000000000..6a967bf8cfb --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IndividualService.java @@ -0,0 +1,372 @@ +package org.egov.hrms.service; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; +import java.util.UUID; +import java.util.stream.Collectors; + +import digit.models.coremodels.AuditDetails; +import digit.models.coremodels.user.enums.UserType; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.Role; +import org.egov.common.models.individual.Address; +import org.egov.common.models.individual.AddressType; +import org.egov.common.models.individual.Gender; +import org.egov.common.models.individual.Identifier; +import org.egov.common.models.individual.Individual; +import org.egov.common.models.individual.IndividualBulkResponse; +import org.egov.common.models.individual.IndividualRequest; +import org.egov.common.models.individual.IndividualResponse; +import org.egov.common.models.individual.Name; +import org.egov.common.models.individual.UserDetails; +import org.egov.hrms.config.PropertiesManager; +import org.egov.hrms.repository.RestCallRepository; +import org.egov.hrms.utils.HRMSConstants; +import org.egov.hrms.web.contract.User; +import org.egov.hrms.web.contract.UserRequest; +import org.egov.hrms.web.contract.UserResponse; +import org.egov.hrms.web.models.IndividualSearch; +import org.egov.hrms.web.models.IndividualSearchRequest; +import org.springframework.beans.factory.annotation.Autowired; + +import static org.egov.hrms.utils.HRMSConstants.SYSTEM_GENERATED; + +@Slf4j +public class IndividualService implements UserService { + + private final PropertiesManager propertiesManager; + + private final RestCallRepository restCallRepository; + + @Autowired + public IndividualService(PropertiesManager propertiesManager, + RestCallRepository restCallRepository) { + this.propertiesManager = propertiesManager; + this.restCallRepository = restCallRepository; + } + + + @Override + public UserResponse createUser(UserRequest userRequest) { + IndividualRequest request = mapToIndividualRequest(userRequest); + StringBuilder uri = new StringBuilder(); + uri.append(propertiesManager.getIndividualHost()); + uri.append(propertiesManager.getIndividualCreateEndpoint()); + IndividualResponse response = restCallRepository + .fetchResult(uri, request, IndividualResponse.class); + UserResponse userResponse = null; + if (response != null && response.getIndividual() != null) { + log.info("response received from individual service"); + userResponse = mapToUserResponse(response); + } + return userResponse; + } + + /** + * Updates a user by searching for the corresponding individual and updating their details. + * + * Steps: + * 1. Map UserRequest to IndividualSearchRequest. + * 2. Fetch individual data using tenant ID and search request. + * 3. Return null if no individual is found. + * 4. Prepare an IndividualRequest for update. + * 5. Construct the update endpoint URI. + * 6. Perform REST call to update individual. + * 7. Map response to UserResponse if successful. + * 8. Return UserResponse. + * TODO FIXME + * @param userRequest The request object containing user details to be updated. + * @return UserResponse containing updated user information, or null if no individual was found. + */ + @Override + public UserResponse updateUser(UserRequest userRequest) { + // Map the UserRequest to an IndividualSearchRequest + IndividualSearchRequest individualSearchRequest = mapToIndividualSearchRequest(userRequest); + + // Fetch the individual response from the individual service + IndividualBulkResponse individualSearchResponse = + getIndividualResponse(userRequest.getUser().getTenantId(), individualSearchRequest); + + UserResponse userResponse = null; + + // Check if the individual search response is null or contains no individuals + if (individualSearchResponse == null || individualSearchResponse.getIndividual() == null || individualSearchResponse.getIndividual().isEmpty()) { + return userResponse; // Return null if no individual is found + } + + // Get the first individual from the search response + Individual individual = individualSearchResponse.getIndividual().get(0); + + // Map the found individual and the user request to an IndividualRequest for update + IndividualRequest updateRequest = mapToIndividualUpdateRequest(individual, userRequest); + + // Build the URI for the update endpoint + StringBuilder uri = new StringBuilder(); + uri.append(propertiesManager.getIndividualHost()); + uri.append(propertiesManager.getIndividualUpdateEndpoint()); + + // Make a REST call to update the individual + IndividualResponse response = restCallRepository + .fetchResult(uri, updateRequest, IndividualResponse.class); + + // If the response is not null and contains an updated individual, map it to UserResponse + if (response != null && response.getIndividual() != null) { + log.info("Response received from individual service"); + userResponse = mapToUserResponse(response); + } + + // Return the UserResponse + return userResponse; + } + + + private IndividualRequest mapToIndividualUpdateRequest(Individual individual, UserRequest userRequest) { + Individual updatedIndividual = Individual.builder() + .id(individual.getId()) + .userId(individual.getUserId()) + .userUuid(individual.getUserUuid()) + .isSystemUser(true) + .isSystemUserActive(userRequest.getUser().getActive()) + .name(Name.builder() + .givenName(userRequest.getUser().getName()) + .build()) + .gender(Gender.fromValue(userRequest.getUser().getGender())) + .email(userRequest.getUser().getEmailId()) + .mobileNumber(userRequest.getUser().getMobileNumber()) + .dateOfBirth(convertMillisecondsToDate(userRequest.getUser().getDob())) + .tenantId(userRequest.getUser().getTenantId()) + .address(Collections.singletonList(Address.builder() + .type(AddressType.CORRESPONDENCE) + .addressLine1(userRequest.getUser().getCorrespondenceAddress()) + .clientReferenceId(String.valueOf(UUID.randomUUID())) + .isDeleted(Boolean.FALSE) + .build())) + /* + * FIXME (HCM specific change) clientReferenceId is the primary key in the individual table of the FrontEnd Worker Application's local database. + */ + // Generating a unique client reference ID using UUID + .clientReferenceId(individual.getClientReferenceId()) + .userDetails(UserDetails.builder() + .username(userRequest.getUser().getUserName()) + .password(userRequest.getUser().getPassword()) + .tenantId(userRequest.getUser().getTenantId()) + .roles(userRequest.getUser().getRoles().stream().map(role -> Role.builder() + .code(role.getCode()) + .name(role.getName()) + .tenantId(userRequest.getUser().getTenantId()) + .description(role.getDescription()) + .build()).collect(Collectors.toList())) + .userType(individual.getUserDetails().getUserType()) + .build()) + .isDeleted(Boolean.FALSE) + .clientAuditDetails(AuditDetails.builder() + .createdBy(individual.getAuditDetails().getCreatedBy()) + .createdTime(individual.getAuditDetails().getCreatedTime()) + .lastModifiedBy(userRequest.getRequestInfo().getUserInfo().getUuid()).build()) + .rowVersion(userRequest.getUser().getRowVersion()) + .build(); + return IndividualRequest.builder() + .requestInfo(userRequest.getRequestInfo()) + .individual(updatedIndividual) + .build(); + } + + private IndividualSearchRequest mapToIndividualSearchRequest(UserRequest userRequest) { + return IndividualSearchRequest.builder() + .requestInfo(userRequest.getRequestInfo()) + .individual( + IndividualSearch.builder() + .id(Collections.singletonList(userRequest.getUser().getUuid())) + .userUuid(userRequest.getUser().getUserServiceUuid() != null ? Collections.singletonList(userRequest.getUser().getUserServiceUuid()) : null) + .build() + ) + .build(); + } + + @Override + public UserResponse getUser(RequestInfo requestInfo, Map userSearchCriteria ) { + String mobileNumber = (String) userSearchCriteria.get("mobileNumber"); + String username = (String) userSearchCriteria.get(HRMSConstants.HRMS_USER_SEARCH_CRITERA_USERNAME); + List mobileNumberList = null; + List usernameList = null; + if(!StringUtils.isEmpty(mobileNumber)) { + mobileNumberList = Collections.singletonList(mobileNumber); + } + if(!StringUtils.isEmpty(username)) { + usernameList = Collections.singletonList(username); + } + IndividualSearchRequest request = IndividualSearchRequest.builder() + .requestInfo(requestInfo) + .individual(IndividualSearch.builder() + .mobileNumber( + mobileNumberList + ) + .id((List) userSearchCriteria.get("uuid")) + .roleCodes((List) userSearchCriteria.get("roleCodes")) + .username(usernameList) + // given name + .individualName((String) userSearchCriteria + .get(HRMSConstants.HRMS_USER_SEARCH_CRITERA_NAME)) + .type((String) userSearchCriteria.get(HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE)) + .build()) + .build(); + IndividualBulkResponse response = getIndividualResponse((String) userSearchCriteria + .get(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID), + request); + UserResponse userResponse = new UserResponse(); + if (response != null && response.getIndividual() != null && !response.getIndividual().isEmpty()) { + log.info("response received from individual service"); + userResponse = mapToUserResponse(response); + } + return userResponse; + } + + private IndividualBulkResponse getIndividualResponse(String tenantId, IndividualSearchRequest individualSearchRequest) { + return restCallRepository.fetchResult( + new StringBuilder(propertiesManager.getIndividualHost() + + propertiesManager.getIndividualSearchEndpoint() + + "?limit=1000&offset=0&tenantId=" + tenantId), + individualSearchRequest, IndividualBulkResponse.class); + } + + + /** + * Converts a long value representing milliseconds since the epoch to a Date object in the format dd/MM/yyyy. + * + * @param milliseconds the long value representing milliseconds since the epoch. + * @return a Date object in the format dd/MM/yyyy. + */ + private static Date convertMillisecondsToDate(long milliseconds) { + SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy"); + formatter.setTimeZone(TimeZone.getTimeZone("UTC")); + String dateString = formatter.format(new Date(milliseconds)); + try { + return formatter.parse(dateString); + } catch (ParseException e) { + e.printStackTrace(); + return null; + } + } + + private static IndividualRequest mapToIndividualRequest(UserRequest userRequest) { + Individual individual = Individual.builder() + .id(userRequest.getUser().getUuid()) + .userId(userRequest.getUser().getId() != null ? + String.valueOf(userRequest.getUser().getId()) : null) + .userUuid(userRequest.getUser().getUserServiceUuid()) + .isSystemUser(true) + .isSystemUserActive(userRequest.getUser().getActive()) + .name(Name.builder() + .givenName(userRequest.getUser().getName()) + .build()) + .gender(Gender.fromValue(userRequest.getUser().getGender())) + .email(userRequest.getUser().getEmailId()) + .mobileNumber(userRequest.getUser().getMobileNumber()) + .dateOfBirth(convertMillisecondsToDate(userRequest.getUser().getDob())) + .tenantId(userRequest.getUser().getTenantId()) + .address(Collections.singletonList(Address.builder() + .type(AddressType.CORRESPONDENCE) + .addressLine1(userRequest.getUser().getCorrespondenceAddress()) + .clientReferenceId(String.valueOf(UUID.randomUUID())) + .isDeleted(Boolean.FALSE) + .build())) + /* + * FIXME (HCM specific change) clientReferenceId is the primary key in the individual table of the FrontEnd Worker Application's local database. + */ + // Generating a unique client reference ID using UUID + .clientReferenceId(String.valueOf(UUID.randomUUID())) + // Creating a list of identifiers + .identifiers(Collections.singletonList( + // Building a unique identifier + Identifier.builder() + // Generating a unique client reference ID using UUID for the identifier + .clientReferenceId(String.valueOf(UUID.randomUUID())) + // Generating a unique identifier ID using UUID + .identifierId(String.valueOf(UUID.randomUUID())) + // Specifying the type of identifier as SYSTEM_GENERATED + .identifierType(SYSTEM_GENERATED) + .build())) + .userDetails(UserDetails.builder() + .username(userRequest.getUser().getUserName()) + .password(userRequest.getUser().getPassword()) + .tenantId(userRequest.getUser().getTenantId()) + .roles(userRequest.getUser().getRoles().stream().map(role -> Role.builder() + .code(role.getCode()) + .name(role.getName()) + .tenantId(userRequest.getUser().getTenantId()) + .description(role.getDescription()) + .build()).collect(Collectors.toList())) + .userType(UserType.fromValue(userRequest.getUser().getType())) + .build()) + .isDeleted(Boolean.FALSE) + .clientAuditDetails(AuditDetails.builder().createdBy(userRequest.getRequestInfo().getUserInfo().getUuid()).lastModifiedBy(userRequest.getRequestInfo().getUserInfo().getUuid()).build()) + .rowVersion(userRequest.getUser().getRowVersion()) + .build(); + return IndividualRequest.builder() + .requestInfo(userRequest.getRequestInfo()) + .individual(individual) + .build(); + } + + private static UserResponse mapToUserResponse(IndividualResponse response) { + UserResponse userResponse; + userResponse = UserResponse.builder() + .responseInfo(response.getResponseInfo()) + .user(Collections.singletonList(getUser(response.getIndividual()))) + .build(); + return userResponse; + } + + private static UserResponse mapToUserResponse(IndividualBulkResponse response) { + UserResponse userResponse; + userResponse = UserResponse.builder() + .responseInfo(response.getResponseInfo()) + .user(response.getIndividual().stream() + .map(IndividualService::getUser).collect(Collectors.toList())) + .build(); + return userResponse; + } + + + private static User getUser(Individual individual) { + return User.builder() + .id(individual.getUserId() != null ? Long.parseLong(individual.getUserId()) : null) + .mobileNumber(individual.getMobileNumber()) + .name(individual.getName().getGivenName()) + .uuid(individual.getId()) + .userServiceUuid(individual.getUserUuid()) + .active(individual.getIsSystemUserActive()) + .gender(individual.getGender() != null ? individual.getGender().name() : null) + .type(individual.getUserDetails().getUserType().toString()) + .userName(individual.getUserDetails().getUsername()) + .emailId(individual.getEmail()) + .correspondenceAddress(individual.getAddress() != null && !individual.getAddress().isEmpty() + ? individual.getAddress().stream().filter(address -> address.getType() + .equals(AddressType.CORRESPONDENCE)).findFirst() + .orElse(Address.builder().build()) + .getAddressLine1() : null) + .dob(individual.getDateOfBirth().getTime()) + .tenantId(individual.getTenantId()) + .createdBy(individual.getAuditDetails().getCreatedBy()) + .createdDate(individual.getAuditDetails().getCreatedTime()) + .lastModifiedBy(individual.getAuditDetails().getLastModifiedBy()) + .lastModifiedDate(individual.getAuditDetails().getLastModifiedTime()) + .rowVersion(individual.getRowVersion()) + .roles(individual.getUserDetails() + .getRoles().stream().map(role -> org.egov.hrms.model.Role.builder() + .code(role.getCode()) + .tenantId(role.getTenantId()) + .name(role.getName()) + .build()).collect(Collectors.toList())) + + .build(); + } +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/MDMSService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/MDMSService.java new file mode 100644 index 00000000000..9b2d8df55c3 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/MDMSService.java @@ -0,0 +1,189 @@ +package org.egov.hrms.service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.egov.common.contract.request.RequestInfo; +import org.egov.hrms.utils.HRMSConstants; +import org.egov.mdms.model.MasterDetail; +import org.egov.mdms.model.MdmsCriteria; +import org.egov.mdms.model.MdmsCriteriaReq; +import org.egov.mdms.model.MdmsResponse; +import org.egov.mdms.model.ModuleDetail; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.web.client.RestTemplate; + +import lombok.extern.slf4j.Slf4j; + +@Service +@Slf4j +public class MDMSService { + + @Autowired + private RestTemplate restTemplate; + + @Value("${egov.mdms.host}") + private String mdmsHost; + + @Value("${egov.mdms.search.endpoint}") + private String mdmsEndpoint; + + + /** + * Builds cache for MDMS data, this gets refreshed for every call. + * + * @param requestInfo + * @param tenantId + * @return + */ + public Map> getMDMSData(RequestInfo requestInfo, String tenantId){ + MdmsResponse response = fetchMDMSData(requestInfo, tenantId); + Map> masterData = new HashMap<>(); + Map> eachMasterMap = new HashMap<>(); + if(null != response) { + if(!CollectionUtils.isEmpty(response.getMdmsRes().keySet())) { + if(null != response.getMdmsRes().get(HRMSConstants.HRMS_MDMS_COMMON_MASTERS_CODE)){ + eachMasterMap = (Map) response.getMdmsRes().get(HRMSConstants.HRMS_MDMS_COMMON_MASTERS_CODE); + masterData.put(HRMSConstants.HRMS_MDMS_DEPT_CODE, eachMasterMap.get(HRMSConstants.HRMS_MDMS_DEPT_CODE)); + masterData.put(HRMSConstants.HRMS_MDMS_DESG_CODE, eachMasterMap.get(HRMSConstants.HRMS_MDMS_DESG_CODE)); + } + if(null != response.getMdmsRes().get(HRMSConstants.HRMS_MDMS_HR_MASTERS_CODE)) { + eachMasterMap = (Map) response.getMdmsRes().get(HRMSConstants.HRMS_MDMS_HR_MASTERS_CODE); + masterData.put(HRMSConstants.HRMS_MDMS_EMP_STATUS_CODE, eachMasterMap.get(HRMSConstants.HRMS_MDMS_EMP_STATUS_CODE)); + masterData.put(HRMSConstants.HRMS_MDMS_EMP_TYPE_CODE, eachMasterMap.get(HRMSConstants.HRMS_MDMS_EMP_TYPE_CODE)); + masterData.put(HRMSConstants.HRMS_MDMS_QUALIFICATION_CODE, eachMasterMap.get(HRMSConstants.HRMS_MDMS_QUALIFICATION_CODE)); + masterData.put(HRMSConstants.HRMS_MDMS_STREAMS_CODE, eachMasterMap.get(HRMSConstants.HRMS_MDMS_STREAMS_CODE)); + masterData.put(HRMSConstants.HRMS_MDMS_DEPT_TEST_CODE, eachMasterMap.get(HRMSConstants.HRMS_MDMS_DEPT_TEST_CODE)); + masterData.put(HRMSConstants.HRMS_MDMS_DEACT_REASON_CODE, eachMasterMap.get(HRMSConstants.HRMS_MDMS_DEACT_REASON_CODE)); + } + if(null != response.getMdmsRes().get(HRMSConstants.HRMS_AC_ROLES_MASTERS_CODE)) { + eachMasterMap = (Map) response.getMdmsRes().get(HRMSConstants.HRMS_AC_ROLES_MASTERS_CODE); + masterData.put(HRMSConstants.HRMS_MDMS_ROLES_CODE, eachMasterMap.get(HRMSConstants.HRMS_MDMS_ROLES_CODE)); + } + } + } + + return masterData; + + } + + + + /** + * Makes call to the MDMS service to fetch the MDMS data. + * + * @param requestInfo + * @param tenantId + * @return + */ + public MdmsResponse fetchMDMSData(RequestInfo requestInfo, String tenantId) { + StringBuilder uri = new StringBuilder(); + MdmsCriteriaReq request = prepareMDMSRequest(uri, requestInfo, tenantId); + MdmsResponse response = null; + try { + response = restTemplate.postForObject(uri.toString(), request, MdmsResponse.class); + }catch(Exception e) { + log.info("Exception while fetching from MDMS: ",e); + log.info("Request: "+ request); + } + return response; + } + + /** + * Makes call to the MDMS service to fetch the MDMS Boundary data. + * + * @param requestInfo + * @param tenantId + * @return + */ + public MdmsResponse fetchMDMSDataLoc(RequestInfo requestInfo, String tenantId) { + StringBuilder uri = new StringBuilder(); + MdmsCriteriaReq request = prepareMDMSRequestLoc(uri, requestInfo, tenantId); + MdmsResponse response = null; + try { + response = restTemplate.postForObject(uri.toString(), request, MdmsResponse.class); + }catch(Exception e) { + log.info("Exception while fetching from MDMS: ",e); + log.info("Request: "+ request); + } + return response; + } + + /** + * Prepares request for MDMS in order to fetch all the required masters for HRMS. + * + * @param uri + * @param requestInfo + * @param tenantId + * @return + */ + public MdmsCriteriaReq prepareMDMSRequest(StringBuilder uri, RequestInfo requestInfo, String tenantId) { + Map> mapOfModulesAndMasters = new HashMap<>(); + String[] hrMasters = {HRMSConstants.HRMS_MDMS_EMP_STATUS_CODE, HRMSConstants.HRMS_MDMS_EMP_TYPE_CODE, HRMSConstants.HRMS_MDMS_QUALIFICATION_CODE, + HRMSConstants.HRMS_MDMS_SERVICE_STATUS_CODE, HRMSConstants.HRMS_MDMS_STREAMS_CODE, HRMSConstants.HRMS_MDMS_DEACT_REASON_CODE, HRMSConstants.HRMS_MDMS_DEPT_TEST_CODE}; + String[] commonMasters = {HRMSConstants.HRMS_MDMS_DEPT_CODE, HRMSConstants.HRMS_MDMS_DESG_CODE, HRMSConstants.HRMS_MDMS_YEAR_CODE}; + String[] accessControlRoles = {HRMSConstants.HRMS_MDMS_ROLES_CODE}; + mapOfModulesAndMasters.put(HRMSConstants.HRMS_MDMS_COMMON_MASTERS_CODE, Arrays.asList(commonMasters)); + mapOfModulesAndMasters.put(HRMSConstants.HRMS_MDMS_HR_MASTERS_CODE, Arrays.asList(hrMasters)); + mapOfModulesAndMasters.put(HRMSConstants.HRMS_AC_ROLES_MASTERS_CODE, Arrays.asList(accessControlRoles)); + List moduleDetails = new ArrayList<>(); + for(String module: mapOfModulesAndMasters.keySet()) { + ModuleDetail moduleDetail = new ModuleDetail(); + moduleDetail.setModuleName(module); + List masterDetails = new ArrayList<>(); + for(String master: mapOfModulesAndMasters.get(module)) { + MasterDetail masterDetail=null; + if(module.equals(HRMSConstants.HRMS_AC_ROLES_MASTERS_CODE)) + masterDetail = MasterDetail.builder().name(master).filter(HRMSConstants.HRMS_MDMS_AC_ROLES_FILTER).build(); + else + masterDetail = MasterDetail.builder().name(master).filter("[?(@.active == true)].code").build(); + masterDetails.add(masterDetail); + } + moduleDetail.setMasterDetails(masterDetails); + moduleDetails.add(moduleDetail); + } + uri.append(mdmsHost).append(mdmsEndpoint); + MdmsCriteria mdmsCriteria = MdmsCriteria.builder().tenantId(tenantId).moduleDetails(moduleDetails).build(); + return MdmsCriteriaReq.builder().requestInfo(requestInfo).mdmsCriteria(mdmsCriteria).build(); + + } + + + /** + * Prepares request for MDMS in order to fetch all the required masters for Boundary Data. + * + * @param uri + * @param requestInfo + * @param tenantId + * @return + */ + public MdmsCriteriaReq prepareMDMSRequestLoc(StringBuilder uri, RequestInfo requestInfo, String tenantId) { + Map> mapOfModulesAndMasters = new HashMap<>(); + String[] egovLoccation = {HRMSConstants.HRMS_MDMS_TENANT_BOUNDARY_CODE}; + mapOfModulesAndMasters.put(HRMSConstants.HRMS_MDMS_EGOV_LOCATION_MASTERS_CODE, Arrays.asList(egovLoccation)); + List moduleDetails = new ArrayList<>(); + for(String module: mapOfModulesAndMasters.keySet()) { + ModuleDetail moduleDetail = new ModuleDetail(); + moduleDetail.setModuleName(module); + List masterDetails = new ArrayList<>(); + for(String master: mapOfModulesAndMasters.get(module)) { + MasterDetail masterDetail=null; + masterDetail = MasterDetail.builder().name(master).build(); + masterDetails.add(masterDetail); + } + moduleDetail.setMasterDetails(masterDetails); + moduleDetails.add(moduleDetail); + } + uri.append(mdmsHost).append(mdmsEndpoint); + MdmsCriteria mdmsCriteria = MdmsCriteria.builder().tenantId(tenantId).moduleDetails(moduleDetails).build(); + return MdmsCriteriaReq.builder().requestInfo(requestInfo).mdmsCriteria(mdmsCriteria).build(); + + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/NotificationService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/NotificationService.java new file mode 100644 index 00000000000..acb427e4ce7 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/NotificationService.java @@ -0,0 +1,196 @@ +package org.egov.hrms.service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.hrms.model.Employee; +import org.egov.hrms.model.SMSRequest; +import org.egov.hrms.producer.HRMSProducer; +import org.egov.hrms.repository.RestCallRepository; +import org.egov.hrms.utils.HRMSConstants; +import org.egov.hrms.web.contract.EmployeeRequest; +import org.egov.hrms.web.contract.RequestInfoWrapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import com.jayway.jsonpath.JsonPath; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.client.RestTemplate; + +@Service +@Slf4j +public class NotificationService { + + @Autowired + private HRMSProducer producer; + + @Autowired + private RestCallRepository repository; + + @Autowired + private RestTemplate restTemplate; + + @Value("${kafka.topics.notification.sms}") + private String smsTopic; + + @Value("${egov.hrms.employee.app.link}") + private String appLink; + + @Value("${egov.localization.host}") + private String localizationHost; + + @Value("${egov.localization.search.endpoint}") + private String localizationSearchEndpoint; + + @Value("${egov.otp.host}") + private String otpHost; + + @Value("${egov.otp.create.endpoint}") + private String otpCreateEndpoint; + + @Value("${egov.environment.domain}") + private String envHost; + + + + /** + * Sends notification by putting the sms content onto the core-sms topic + * + * @param request + * @param pwdMap + */ + public void sendNotification(EmployeeRequest request, Map pwdMap) { + String message = getMessage(request,HRMSConstants.HRMS_EMP_CREATE_LOCLZN_CODE); + if(StringUtils.isEmpty(message)) { + log.info("SMS content has not been configured for this case"); + return; + } + for(Employee employee: request.getEmployees()) { + message = buildMessage(employee, message, pwdMap); + SMSRequest smsRequest = SMSRequest.builder().mobileNumber(employee.getUser().getMobileNumber()).message(message).build(); + producer.push(smsTopic, smsRequest); + } + } + + public void sendReactivationNotification(EmployeeRequest request){ + String message = getMessage(request,HRMSConstants.HRMS_EMP_REACTIVATE_LOCLZN_CODE); + if(StringUtils.isEmpty(message)) { + log.info("SMS content has not been configured for this case"); + return; + } + RequestInfo requestInfo = request.getRequestInfo(); + for(Employee employee: request.getEmployees()) { + if(employee.getReactivationDetails()!=null && employee.getReActivateEmployee()){ + String OTP = getOTP(employee,requestInfo); + String link = envHost + "employee/user/otp"; + + message = message.replace("{Employee Name}",employee.getUser().getName()).replace("{Username}",employee.getCode()); + message = message.replace("{date}",(employee.getReactivationDetails().get(0).getEffectiveFrom()).toString()); + message = message.replace("{password}",OTP).replace("{link}",link); + + SMSRequest smsRequest = SMSRequest.builder().mobileNumber(employee.getUser().getMobileNumber()).message(message).build(); + log.info(message ); + producer.push(smsTopic, smsRequest); + } + + } + + } + + public String getOTP(Employee employee,RequestInfo requestInfo){ + Map OTPRequest= new HashMap<>(); + Map otp= new HashMap<>(); + otp.put("mobileNumber",employee.getUser().getMobileNumber()); + otp.put("type","passwordreset"); + otp.put("tenantId",employee.getTenantId()); + otp.put("userType","EMPLOYEE"); + otp.put("identity",employee.getUser().getMobileNumber()); + + OTPRequest.put("RequestInfo",requestInfo); + OTPRequest.put("otp",otp); + + Object response = null; + StringBuilder url = new StringBuilder(); + url.append(otpHost).append(otpCreateEndpoint); + try { + response = restTemplate.postForObject(url.toString(), OTPRequest, Map.class); + }catch(Exception e) { + log.error("Exception while creating user: ", e); + return null; + } + String result = JsonPath.read(response, "$.otp.otp"); + return result; + } + + /** + * Gets the message from localization + * + * @param request + * @return + */ + public String getMessage(EmployeeRequest request,String msgCode) { + String tenantId = request.getEmployees().get(0).getTenantId().split("\\.")[0]; + Map> localizedMessageMap = getLocalisedMessages(request.getRequestInfo(), tenantId, + HRMSConstants.HRMS_LOCALIZATION_ENG_LOCALE_CODE, HRMSConstants.HRMS_LOCALIZATION_MODULE_CODE); + return localizedMessageMap.get(HRMSConstants.HRMS_LOCALIZATION_ENG_LOCALE_CODE +"|"+tenantId).get(msgCode); + } + + /** + * Builds msg based on the format + * + * @param employee + * @param message + * @param pwdMap + * @return + */ + public String buildMessage(Employee employee, String message, Map pwdMap) { + message = message.replace("$username", employee.getCode()).replace("$password", pwdMap.get(employee.getUuid())) + .replace("$employeename", employee.getUser().getName()); + message = message.replace("$applink", appLink); + return message; + } + + /** + * Creates a cache for localization that gets refreshed at every call. + * + * @param requestInfo + * @param tenantId + * @param locale + * @param module + * @return + */ + public Map> getLocalisedMessages(RequestInfo requestInfo, String tenantId, String locale, String module) { + Map> localizedMessageMap = new HashMap<>(); + Map mapOfCodesAndMessages = new HashMap<>(); + StringBuilder uri = new StringBuilder(); + RequestInfoWrapper requestInfoWrapper = new RequestInfoWrapper(); + requestInfoWrapper.setRequestInfo(requestInfo); + tenantId = tenantId.split("\\.")[0]; + uri.append(localizationHost).append(localizationSearchEndpoint).append("?tenantId=" + tenantId) + .append("&module=" + module).append("&locale=" + locale); + List codes = null; + List messages = null; + Object result = null; + try { + result = repository.fetchResult(uri, requestInfoWrapper); + codes = JsonPath.read(result, HRMSConstants.HRMS_LOCALIZATION_CODES_JSONPATH); + messages = JsonPath.read(result, HRMSConstants.HRMS_LOCALIZATION_MSGS_JSONPATH); + } catch (Exception e) { + log.error("Exception while fetching from localization: " + e); + } + if (null != result) { + for (int i = 0; i < codes.size(); i++) { + mapOfCodesAndMessages.put(codes.get(i), messages.get(i)); + } + localizedMessageMap.put(locale + "|" + tenantId, mapOfCodesAndMessages); + } + + return localizedMessageMap; + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/UserService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/UserService.java new file mode 100644 index 00000000000..f1c7ee71a66 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/UserService.java @@ -0,0 +1,16 @@ +package org.egov.hrms.service; + +import org.egov.common.contract.request.RequestInfo; +import org.egov.hrms.web.contract.UserRequest; +import org.egov.hrms.web.contract.UserResponse; + +import java.util.Map; + +public interface UserService { + + UserResponse createUser(UserRequest userRequest); + + UserResponse updateUser(UserRequest userRequest); + + UserResponse getUser(RequestInfo requestInfo, Map userSearchCriteria); +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/ErrorConstants.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/ErrorConstants.java new file mode 100644 index 00000000000..1dccb2952f8 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/ErrorConstants.java @@ -0,0 +1,206 @@ +package org.egov.hrms.utils; + +import org.springframework.stereotype.Component; + +@Component +public class ErrorConstants { + + public static final String HRMS_USER_EXIST_MOB_CODE = "ERR_HRMS_USER_EXIST_MOB"; + public static final String HRMS_USER_EXIST_MOB_MSG = "User already exists for the entered mobile number. Use a different mobile number to proceed."; + + public static final String HRMS_USER_EXIST_USERNAME_CODE = "ERR_HRMS_USER_EXIST_USERNAME"; + public static final String HRMS_USER_EXIST_USERNAME_MSG = "User already exists for the entered user name."; + + public static final String HRMS_INVALID_MOB_NO_CODE = "ERR_HRMS_INVALID_MOB_NO"; + public static final String HRMS_INVALID_MOB_NO_MSG = "Invalid mobile number entered."; + + public static final String HRMS_MISSING_ROLES_CODE = "ERR_HRMS_MISSING_ROLES"; + public static final String HRMS_INVALID_ROLES_MSG = "Invalid mobile number entered."; + + public static final String HRMS_INVALID_ROLE_CODE = "ERR_HRMS_INVALID_ROLE"; + public static final String HRMS_INVALID_ROLE_MSG = "Invalid role assigned to the employee."; + + public static final String HRMS_INVALID_EMP_STATUS_CODE = "ERR_HRMS_INVALID_EMP_STATUS_ROLE"; + public static final String HRMS_INVALID_EMP_STATUS_MSG = "Invalid employment status entered."; + + public static final String HRMS_INVALID_EMP_TYPE_CODE = "ERR_HRMS_INVALID_EMP_TYPE"; + public static final String HRMS_INVALID_EMP_TYPE_MSG = "Invalid employee type entered."; + + public static final String HRMS_INVALID_DATE_OF_APPOINTMENT_CODE = "ERR_HRMS_INVALID_DATE_OF_APPOINTMENT"; + public static final String HRMS_INVALID_DATE_OF_APPOINTMENT_MSG = "Invalid employee date of appointment entered by the user."; + + public static final String HRMS_INVALID_DATE_OF_APPOINTMENT_DOB_CODE = "ERR_HRMS_INVALID_DATE_OF_APPOINTMENT_DOB"; + public static final String HRMS_INVALID_DATE_OF_APPOINTMENT_DOB_MSG = "Employee date of appointment can not be before date of birth."; + + public static final String HRMS_INVALID_DOB_CODE = "ERR_HRMS_INVALID_DOB"; + public static final String HRMS_INVALID_DOB_MSG = "Invalid date of birth entered."; + + public static final String HRMS_INVALID_CURRENT_ASSGN_CODE = "ERR_HRMS_INVALID_CURRENT_ASSGN"; + public static final String HRMS_INVALID_CURRENT_ASSGN_MSG = "There should be exactly one current assignment for the employee."; + + public static final String HRMS_OVERLAPPING_ASSGN_CODE = "ERR_HRMS_OVERLAPPING_ASSGN"; + public static final String HRMS_OVERLAPPING_ASSGN_MSG = "There should not be overlapping period of assignments for the employee."; + + public static final String HRMS_OVERLAPPING_ASSGN_CURRENT_CODE = "ERR_HRMS_OVERLAPPING_ASSGN_CURRENT"; + public static final String HRMS_OVERLAPPING_ASSGN_CURRENT_MSG = "Period of assignements of employee should not be after current assignment."; + + public static final String HRMS_INVALID_DEPT_CODE = "ERR_HRMS_INVALID_DEPT"; + public static final String HRMS_INVALID_DEPT_MSG = "Invalid department of employee entered."; + + public static final String HRMS_INVALID_DESG_CODE = "ERR_HRMS_INVALID_DESG"; + public static final String HRMS_INVALID_DESG_MSG = "Invalid designation of employee."; + + public static final String HRMS_INVALID_ASSIGNMENT_PERIOD_CODE = "ERR_HRMS_INVALID_ASSIGNMENT_PERIOD"; + public static final String HRMS_INVALID_ASSIGNMENT_PERIOD_MSG = "Invalid period of assignment (From date - To date)."; + + public static final String HRMS_INVALID_ASSIGNMENT_CURRENT_TO_DATE_CODE = "ERR_HRMS_INVALID_ASSIGNMENT_CURRENT_TO_DATE"; + public static final String HRMS_INVALID_ASSIGNMENT_CURRENT_TO_DATE_MSG = "To Date field should be blank for current assignment of the employee."; + + public static final String HRMS_OVERLAPPING_SERVICEHISTORY_CURRENT_CODE = "ERR_HRMS_OVERLAPPING_SERVICEHISTORY_CURRENT"; + public static final String HRMS_OVERLAPPING_SERVICEHISTORY_CURRENT_MSG = "Period of service details of employee should not be after current assignment!"; + + + public static final String HRMS_INVALID_ASSIGNMENT_NON_CURRENT_TO_DATE_CODE = "ERR_HRMS_INVALID_ASSIGNMENT_NOT_CURRENT_TO_DATE"; + public static final String HRMS_INVALID_ASSIGNMENT_NON_CURRENT_TO_DATE_MSG = "To date field should not be blank for non current assignment of the employee."; + + public static final String HRMS_INVALID_ASSIGNMENT_DATES_CODE = "ERR_HRMS_INVALID_ASSIGNMENT_DATES"; + public static final String HRMS_INVALID_ASSIGNMENT_DATES_MSG = "Employee period of assignment (From Date or To date) can not be before date of birth."; + + public static final String HRMS_INVALID_ASSIGNMENT_DATES_APPOINTMENT_CODE = "ERR_HRMS_INVALID_ASSIGNMENT_DATES_APPOINTMENT"; + public static final String HRMS_INVALID_ASSIGNMENT_DATES_APPOINTMENT_MSG = "Employee period of assignment (From Date or To date) can not be before date of appointment."; + + public static final String HRMS_INVALID_SERVICE_STATUS_CODE = "ERR_HRMS_INVALID_SERVICE_STATUS"; + public static final String HRMS_INVALID_SERVICE_STATUS_MSG = "Service stataus of employee is invalid."; + + public static final String HRMS_INVALID_SERVICE_PERIOD_CODE = "ERR_HRMS_INVALID_SERVICE_PERIOD"; + public static final String HRMS_INVALID_SERVICE_PERIOD_MSG = "Service period (From date or To date) of employee is invalid."; + + public static final String HRMS_INVALID_SERVICE_DATES_CODE = "ERR_HRMS_INVALID_SERVICE_DATES"; + public static final String HRMS_INVALID_SERVICE_DATES_MSG = "Employee service period (From date or To date) can not be before date of birth."; + + public static final String HRMS_INVALID_SERVICE_CURRENT_TO_DATE_CODE = "ERR_HRMS_INVALID_SERVICE_CURRENT_TO_DATE"; + public static final String HRMS_INVALID_SERVICE_CURRENT_TO_DATE_MSG = "To Date of service period should be blank for currently working employees."; + + public static final String HRMS_INVALID_SERVICE_NON_CURRENT_TO_DATE_CODE = "ERR_HRMS_INVALID_SERVICE_NOT_CURRENT_TO_DATE"; + public static final String HRMS_INVALID_SERVICE_NON_CURRENT_TO_DATE_MSG = "To Date of service period should not be blank for currently non working employees."; + + public static final String HRMS_INVALID_CURRENT_SERVICE_CODE = "ERR_HRMS_INVALID_SERVICE_ASSGN"; + public static final String HRMS_INVALID_CURRENT_SERVICE_MSG = "There should be maximum one currently working service for the employee."; + + public static final String HRMS_INVALID_QUALIFICATION_CODE = "ERR_HRMS_INVALID_QUALIFICATION"; + public static final String HRMS_INVALID_QUALIFICATION_MSG = "Qualification of the employee is invalid."; + + public static final String HRMS_INVALID_EDUCATIONAL_STREAM_CODE = "ERR_HRMS_INVALID_EDUCATIONAL_STREAM"; + public static final String HRMS_INVALID_EDUCATIONAL_STREAM_MSG = "Education stream of the employee is invalid."; + + public static final String HRMS_INVALID_EDUCATIONAL_PASSING_YEAR_CODE = "ERR_HRMS_INVALID_EDUCATIONAL_PASSING_YEAR"; + public static final String HRMS_INVALID_EDUCATIONAL_PASSING_YEAR_MSG = "Education year of passing of the employee can not be before date of birth."; + + public static final String HRMS_INVALID_DEPARTMENTAL_TEST_CODE = "ERR_HRMS_INVALID_DEPARTMENTAL_TEST"; + public static final String HRMS_INVALID_DEPARTMENTAL_TEST_MSG = "Departmental evaluation test of the employee is invalid."; + + public static final String HRMS_INVALID_DEPARTMENTAL_TEST_PASSING_YEAR_CODE = "ERR_HRMS_INVALID_DEPARTMENTAL_TEST_PASSING_YEAR"; + public static final String HRMS_INVALID_DEPARTMENTAL_TEST_PASSING_YEAR_MSG = "Departmental evaluation test passing year of the employee can not be before date of birth."; + + public static final String HRMS_INVALID_DEACT_REQUEST_CODE = "ERR_HRMS_INVALID_DEACT_REQUEST"; + public static final String HRMS_INVALID_DEACT_REQUEST_MSG = "Employee active flag should be set as false during deactivation."; + + public static final String HRMS_INVALID_DEACT_REASON_CODE = "ERR_HRMS_INVALID_DEACT_REASON"; + public static final String HRMS_INVALID_DEACT_REASON_MSG = "Employee deactivation reason is invalid."; + + public static final String HRMS_UPDATE_JURISDICTION_INCOSISTENT_CODE = "ERR_HRMS_UPDATE_JURISDICTION_INCOSISTENT"; + public static final String HRMS_UPDATE_JURISDICTION_INCOSISTENT_MSG = "Jurisdiction data in an update request should contain all previously entered data."; + + public static final String HRMS_UPDATE_ASSIGNEMENT_INCOSISTENT_CODE = "ERR_HRMS_UPDATE_ASSIGNEMENT_INCOSISTENT"; + public static final String HRMS_UPDATE_ASSIGNEMENT_INCOSISTENT_MSG = "Assignment data in an update request should contain all previously entered data."; + + public static final String HRMS_UPDATE_TESTS_INCOSISTENT_CODE = "ERR_HRMS_UPDATE_TESTS_INCOSISTENT"; + public static final String HRMS_UPDATE_TESTS_INCOSISTENT_MSG = "Employee evaluation test data in an update request should contain all previously entered data."; + + public static final String HRMS_UPDATE_EDUCATION_INCOSISTENT_CODE = "ERR_HRMS_UPDATE_EDUCATION_INCOSISTENT"; + public static final String HRMS_UPDATE_EDUCATION_INCOSISTENT_MSG = "Education data in an update request should contain all previously entered data."; + + public static final String HRMS_UPDATE_SERVICE_HISTORY_INCOSISTENT_CODE = "ERR_HRMS_UPDATE_SERVICE_HISTORY_INCOSISTENT"; + public static final String HRMS_UPDATE_SERVICE_HISTORY_INCOSISTENT_MSG = "Service history data in an update request should contain all previously entered data."; + + public static final String HRMS_UPDATE_DOCUMENT_INCOSISTENT_CODE = "ERR_HRMS_UPDATE_DOCUMENT_INCOSISTENT"; + public static final String HRMS_UPDATE_DOCUMENT_INCOSISTENT_MSG = "Employee document data in an update request should contain all previously entered data."; + + public static final String HRMS_UPDATE_DEACT_DETAILS_INCOSISTENT_CODE = "ERR_HRMS_UPDATE_DEACT_DETAILS_INCOSISTENT"; + public static final String HRMS_UPDATE_DEACT_DETAILS_INCOSISTENT_MSG = "Employee deactivation data in an update request should contain all previously entered data."; + + public static final String HRMS_UPDATE_NULL_ID_CODE = "ERR_HRMS_UPDATE_NULL_ID"; + public static final String HRMS_UPDATE_NULL_ID_MSG = "Employee ID in an update request should not be null."; + + public static final String HRMS_UPDATE_NULL_CODE_CODE = "ERR_HRMS_UPDATE_NULL"; + public static final String HRMS_UPDATE_NULL_CODE_MSG = "Employee Code in an update request should not be null."; + + public static final String HRMS_UPDATE_NULL_UUID_CODE = "ERR_HRMS_UPDATE_NULL_UUID"; + public static final String HRMS_UPDATE_NULL_UUID_MSG = "Employee UUID in an update request should not be null."; + + public static final String HRMS_USER_CREATION_FAILED_CODE = "ERR_HRMS_USER_CREATION_FAILED"; + public static final String HRMS_USER_CREATION_FAILED_MSG = "User creation failed at the user service."; + + public static final String HRMS_USER_UPDATION_FAILED_CODE = "ERR_HRMS_USER_UPDATION_FAILED"; + public static final String HRMS_USER_UPDATION_FAILED_MSG = "User updation failed at the user service."; + + public static final String HRMS_INVALID_SEARCH_REQ_CODE = "ERR_HRMS_INVALID_SEARCH_REQ"; + public static final String HRMS_INVALID_SEARCH_REQ_MSG = "Open search is disabled for this user."; + + public static final String HRMS_INVALID_JURISDICTION_HEIRARCHY_CODE = "ERR_HRMS_INVALID_JURISDICTION_HEIRARCHY"; + public static final String HRMS_INVALID_JURISDICTION_HEIRARCHY_MSG = "Jurisiction hierarchy value is invalid."; + + public static final String HRMS_INVALID_JURISDICTION_BOUNDARY_TYPE_CODE = "ERR_HRMS_INVALID_BOUNDARY_TYPE_HEIRARCHY"; + public static final String HRMS_INVALID_JURISDICTION_BOUNDARY_TYPE_MSG = "Jurisiction boundary type value is invalid."; + + public static final String HRMS_INVALID_JURISDICTION_BOUNDARY_CODE = "ERR_HRMS_INVALID_JURISDICTION_BOUNDARY"; + public static final String HRMS_INVALID_JURISDICTION_BOUNDARY_MSG = "Jurisiction boundary value is invalid."; + + public static final String HRMS_INVALID_JURISDICTION_ACTIIEV_NULL_CODE = "ERR_HRMS_INVALID_JURISDICTION_ACTIIEV_NULL"; + public static final String HRMS_INVALID_JURISDICTION_ACTIIEV_NULL_MSG = "Jurisiction should have atleast 1 active data"; + + public static final String HRMS_INVALID_SEARCH_AOD_CODE = "ERR_HRMS_INVALID_SEARCH_AOD"; + public static final String HRMS_INVALID_SEARCH_AOD_MSG = "Along with as on date, atleast one department and designation need to be passed as search criteria."; + + public static final String HRMS_INVALID_SEARCH_ROLES_CODE = "ERR_HRMS_INVALID_SEARCH_ROLES"; + public static final String HRMS_INVALID_SEARCH_ROLES_MSG = "For search based on roles, passing of tenant id is mandatory."; + + public static final String HRMS_INVALID_SEARCH_USER_CODE = "ERR_HRMS_INVALID_SEARCH_USER"; + public static final String HRMS_INVALID_SEARCH_USER_MSG = "For search based on phone number and name, passing of tenant id is mandatory."; + + public static final String HRMS_UPDATE_EMPLOYEE_CODE_CHANGE_CODE = "ERR_HRMS_UPDATE_EMPLOYEE_CODE_CHANGE"; + public static final String HRMS_UPDATE_EMPLOYEE_CODE_CHANGE_MSG = "Employee code can not be changed in an update request."; + public static final String HRMS_UPDATE_EMPLOYEE_NOT_EXIST_CODE = "ERR_HRMS_UPDATE_EMPLOYEE_NOT_EXIST_CODE"; + public static final String HRMS_UPDATE_EMPLOYEE_NOT_EXIST_MSG = "No employee found for given UUID."; + + public static final String HRMS_UPDATE_EXISTING_MOBNO_CODE = "ERR_HRMS_UPDATE_EXISTING_MOBNO"; + public static final String HRMS_UPDATE_EXISTING_MOBNO_MSG = "User exist for given mobile no"; + + public static final String HRMS_BULK_CREATE_DUPLICATE_MOBILE_CODE = "ERR_HRMS_BULK_CREATE_DUPLICATE_MOBILE"; + public static final String HRMS_BULK_CREATE_DUPLICATE_MOBILE_MSG = "Bulk request has duplicate mobile number "; + + public static final String HRMS_BULK_CREATE_DUPLICATE_EMPCODE_CODE = "ERR_HRMS_BULK_CREATE_DUPLICATE_EMPCODE"; + public static final String HRMS_BULK_CREATE_DUPLICATE_EMPCODE_MSG = "Bulk request has duplicate employee code "; + + public static final String HRMS_UPDATE_DEACT_DETAILS_INCORRECT_EFFECTIVEFROM_CODE = "ERR_HRMS_UPDATE_DEACT_DETAILS_INCORRECT_EFFECTIVEFROM"; + public static final String HRMS_UPDATE_DEACT_DETAILS_INCORRECT_EFFECTIVEFROM_MSG = "Employee deactivation effective date should be current date only."; + + public static final String HRMS_GENERATE_ID_ERROR_CODE = "ERR_HRMS_GENERATE_ID_ERROR"; + public static final String HRMS_GENERATE_ID_ERROR_MSG = "Unable to create ids " ; + + public static final String HRMS_EMPLOYEE_COUNT_ERROR_CODE = "ERR_HRMS_COUNT_EMP"; + public static final String HRMS_EMPLOYEE_COUNT_ERROR_MSG = "Please provide tenantid to get count of the employee"; + + public static final String HRMS_UPDATE_REACT_DETAILS_INCORRECT_EFFECTIVEFROM_CODE = "ERR_HRMS_UPDATE_REACT_DETAILS_INCORRECT_EFFECTIVEFROM"; + public static final String HRMS_UPDATE_REACT_DETAILS_INCORRECT_EFFECTIVEFROM_MSG = "Employee reactivation effective date should be between deactivation date and current date."; + + public static final String CITIZEN_TYPE_CODE = "CITIZEN"; + + public static final String HRMS_INVALID_SEARCH_CITIZEN_CODE = "ERR_HRMS_INVALID_SEARCH_CITIZEN"; + public static final String HRMS_INVALID_SEARCH_CITIZEN_MSG = "Citizen are not allowed to access employee search with Ids."; + + public static final String HRMS_PASSWORD_REQUIRED = "ERR_HRMS_PASSWORD_REQUIRED"; + + public static final String HRMS_PASSWORD_REQUIRED_MSG = "Password is required"; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/HRMSConstants.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/HRMSConstants.java new file mode 100644 index 00000000000..0d01b642d97 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/HRMSConstants.java @@ -0,0 +1,64 @@ +package org.egov.hrms.utils; + +import org.springframework.stereotype.Component; + +@Component +public class HRMSConstants { + + public static final String HRMS_MDMS_COMMON_MASTERS_CODE = "common-masters"; + public static final String HRMS_MDMS_HR_MASTERS_CODE = "egov-hrms"; + public static final String HRMS_AC_ROLES_MASTERS_CODE = "ACCESSCONTROL-ROLES"; + public static final String HRMS_MDMS_EGOV_LOCATION_MASTERS_CODE = "egov-location"; + + public static final String HRMS_MDMS_DEPT_CODE = "Department"; + public static final String HRMS_MDMS_DESG_CODE = "Designation"; + public static final String HRMS_MDMS_EMP_STATUS_CODE = "EmployeeStatus"; + public static final String HRMS_MDMS_EMP_TYPE_CODE = "EmployeeType"; + public static final String HRMS_MDMS_SERVICE_STATUS_CODE = "ServiceStatus"; + public static final String HRMS_MDMS_ROLES_CODE = "roles"; + public static final String HRMS_MDMS_QUALIFICATION_CODE = "Degree"; + public static final String HRMS_MDMS_STREAMS_CODE = "Specalization"; + public static final String HRMS_MDMS_YEAR_CODE = "Year"; + public static final String HRMS_MDMS_DEPT_TEST_CODE = "EmploymentTest"; + public static final String HRMS_MDMS_DEACT_REASON_CODE = "DeactivationReason"; + public static final String HRMS_MDMS_TENANT_BOUNDARY_CODE = "TenantBoundary"; + + public static final String HRMS_LOCALIZATION_CODES_JSONPATH = "$.messages.*.code"; + public static final String HRMS_LOCALIZATION_MSGS_JSONPATH = "$.messages.*.message"; + + + public static final String HRMS_EMP_CREATE_LOCLZN_CODE = "hrms.employee.create.notification"; + public static final String HRMS_EMP_REACTIVATE_LOCLZN_CODE = "hrms.employee.reactivation.notification"; + public static final String HRMS_LOCALIZATION_MODULE_CODE = "egov-hrms"; + public static final String HRMS_LOCALIZATION_ENG_LOCALE_CODE = "en_IN"; + public static final String HRMS_TENANTBOUNDARY_HIERARCHY_JSONPATH = "$.TenantBoundary[?(@.boundary.code ==\"%s\")].hierarchyType.code"; + public static final String HRMS_TENANTBOUNDARY_BOUNDARY_TYPE_JSONPATH ="$.TenantBoundary[?(@.hierarchyType.name==\"%1$s\" && @.boundary.code ==\"%2$s\")]..label"; + public static final String HRMS_TENANTBOUNDARY_BOUNDARY_VALUE_JSONPATH ="$.TenantBoundary[?(@.hierarchyType.name==\"%1$s\" && @.boundary.code ==\"%2$s\")]..code"; + + public static final String HRMS_MDMS_AC_ROLES_FILTER = "[?(@.code != \"CITIZEN\")].code"; + public static final String HRMS_MDMS_CODE_FLITER = "[?(@.active == true)].code"; + + public static final String HRMS_USER_SEARCH_CRITERA_UUID = "uuid"; + public static final String HRMS_USER_SEARCH_CRITERA_ROLECODES = "roleCodes"; + public static final String HRMS_USER_SEARCH_CRITERA_TENANTID = "tenantId"; + public static final String HRMS_USER_SEARCH_CRITERA_MOBILENO = "mobileNumber"; + public static final String HRMS_USER_SEARCH_CRITERA_NAME = "name"; + public static final String HRMS_USER_SEARCH_CRITERA_USERNAME = "UserName"; + public static final String HRMS_USER_SERACH_CRITERIA_USERTYPE = "EMPLOYEE"; + public static final String HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE = "userType"; + + public static final String INTERNALMICROSERVICEROLE_NAME = "Internal Microservice Role"; + + public static final String INTERNALMICROSERVICEROLE_CODE = "INTERNAL_MICROSERVICE_ROLE"; + + public static final String INTERNALMICROSERVICEUSER_NAME = "Internal Microservice User"; + + public static final String INTERNALMICROSERVICEUSER_USERNAME = "INTERNAL_USER"; + + public static final String INTERNALMICROSERVICEUSER_MOBILENO = "9999999999"; + + public static final String INTERNALMICROSERVICEUSER_TYPE = "SYSTEM"; + + public static final String SYSTEM_GENERATED = "SYSTEM_GENERATED"; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/HRMSUtils.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/HRMSUtils.java new file mode 100644 index 00000000000..014a7a2c005 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/HRMSUtils.java @@ -0,0 +1,72 @@ +package org.egov.hrms.utils; + +import java.security.SecureRandom; +import java.util.List; +import java.util.Random; + +import org.egov.hrms.web.contract.EmployeeSearchCriteria; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +@Service +public class HRMSUtils { + + @Value("${egov.hrms.default.pwd.length}") + private Integer pwdLength; + + @Value("${egov.pwd.allowed.special.characters}") + private String allowedPasswordSpecialCharacters; + + /** + * Generates random password for the user to login. Process: + * 1. Takes a list of parameters for password + * 2. Applies a random select logic and generates a password of constant length. + * 3. The length of the password is configurable. + * + * @param params + * @return + */ + public String generatePassword(List params) { + StringBuilder password = new StringBuilder(); + SecureRandom random = new SecureRandom(); + params.add(allowedPasswordSpecialCharacters); + try { + for(int i = 0; i < params.size(); i++) { + String param = params.get(i); + String val; + if(param.length() == 1) + val = param; + else + val = param.split("")[random.nextInt(param.length() - 1)]; + if(val.equals(".") || val.equals("-") || val.equals(" ")) + password.append("x"); + else + password.append(val); + if(password.length() == pwdLength) + break; + else { + if(i == params.size() - 1) + i = 0; + } + } + }catch(Exception e) { + password.append("123456"); + } + + return password.toString().replaceAll("\\s+", ""); + } + + public boolean isAssignmentSearchReqd(EmployeeSearchCriteria criteria) { + return (! CollectionUtils.isEmpty(criteria.getPositions()) || null != criteria.getAsOnDate() + || !CollectionUtils.isEmpty(criteria.getDepartments()) || !CollectionUtils.isEmpty(criteria.getDesignations())); + } + + public String generateMobileNumber() { + Random random = new Random(); + int min = 100000000; + int max = 999999999; + int mobileNumber = random.nextInt(max - min + 1) + min; + return Integer.toString(mobileNumber); + } +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/ResponseInfoFactory.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/ResponseInfoFactory.java new file mode 100644 index 00000000000..e82744a00c0 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/ResponseInfoFactory.java @@ -0,0 +1,26 @@ +package org.egov.hrms.utils; + + +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.stereotype.Component; + +@Component +public class ResponseInfoFactory { + + public ResponseInfo createResponseInfoFromRequestInfo(final RequestInfo requestInfo, final Boolean success) { + + final String apiId = requestInfo != null ? requestInfo.getApiId() : ""; + final String ver = requestInfo != null ? requestInfo.getVer() : ""; + Long ts = null; + if(requestInfo!=null) + ts= requestInfo.getTs(); + final String resMsgId = "uief87324"; // FIXME : Hard-coded + final String msgId = requestInfo != null ? requestInfo.getMsgId() : ""; + final String responseStatus = success ? "successful" : "failed"; + + return ResponseInfo.builder().apiId(apiId).ver(ver).ts(ts).resMsgId(resMsgId).msgId(msgId).resMsgId(resMsgId) + .status(responseStatus).build(); + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeRequest.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeRequest.java new file mode 100644 index 00000000000..87b2b42d207 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeRequest.java @@ -0,0 +1,76 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.web.contract; + +import java.util.List; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +import org.egov.common.contract.request.RequestInfo; +import org.egov.hrms.model.Employee; +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Validated +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class EmployeeRequest { + + @NotNull + @JsonProperty("RequestInfo") + private RequestInfo requestInfo; + + @Valid + @NotEmpty + @JsonProperty("Employees") + private List employees; + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeResponse.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeResponse.java new file mode 100644 index 00000000000..6fb5141aeed --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeResponse.java @@ -0,0 +1,72 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.web.contract; + +import java.util.List; + +import org.egov.common.contract.response.ResponseInfo; +import org.egov.hrms.model.Employee; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +@Builder +@AllArgsConstructor +@EqualsAndHashCode +@Getter +@NoArgsConstructor +@Setter +@ToString +public class EmployeeResponse { + + @JsonProperty("ResponseInfo") + private ResponseInfo responseInfo; + + @JsonProperty("Employees") + private List employees; + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeSearchCriteria.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeSearchCriteria.java new file mode 100644 index 00000000000..f5a3f9dfca6 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeSearchCriteria.java @@ -0,0 +1,75 @@ +package org.egov.hrms.web.contract; + +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.CollectionUtils; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +import javax.validation.constraints.Size; + + +@AllArgsConstructor +@Getter +@NoArgsConstructor +@Setter +@ToString +@Builder +public class EmployeeSearchCriteria { + + public List codes; + + public List names; + + public List departments; + + public List designations; + + public Long asOnDate; + + public List roles; + + public List ids; + + public List employeestatuses; + + public List employeetypes; + + public List uuids; + + public List positions; + + public Boolean isActive; + + @Size(max = 250) + public String tenantId; + + public String phone; + + public Integer offset; + + public Integer limit; + + private Boolean includeUnassigned = false; + + + public boolean isCriteriaEmpty(EmployeeSearchCriteria criteria) { + if(CollectionUtils.isEmpty(criteria.getCodes()) && CollectionUtils.isEmpty(criteria.getNames()) + && CollectionUtils.isEmpty(criteria.getDepartments()) && CollectionUtils.isEmpty(criteria.getDesignations()) + && CollectionUtils.isEmpty(criteria.getIds()) && CollectionUtils.isEmpty(criteria.getEmployeestatuses()) + && CollectionUtils.isEmpty(criteria.getEmployeetypes()) && CollectionUtils.isEmpty(criteria.getUuids()) + && CollectionUtils.isEmpty(criteria.getPositions()) && StringUtils.isEmpty(criteria.getTenantId()) + && CollectionUtils.isEmpty(criteria.getRoles()) && null == criteria.getAsOnDate()) { + return true; + }else { + return false; + } + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdGenerationRequest.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdGenerationRequest.java new file mode 100644 index 00000000000..9116d5835f3 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdGenerationRequest.java @@ -0,0 +1,64 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) <2015> eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ +package org.egov.hrms.web.contract; + +import java.util.List; + +import org.egov.common.contract.request.RequestInfo; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class IdGenerationRequest { + + @JsonProperty("RequestInfo") + private RequestInfo requestInfo; + + private List idRequests; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdGenerationResponse.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdGenerationResponse.java new file mode 100644 index 00000000000..3bcb4d1a7f3 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdGenerationResponse.java @@ -0,0 +1,65 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) <2015> eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ +package org.egov.hrms.web.contract; + +import java.util.List; + +import org.egov.common.contract.response.ResponseInfo; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +@AllArgsConstructor +@NoArgsConstructor +public class IdGenerationResponse { + + private ResponseInfo responseInfo; + + private ResponseInfo ResponseInfo; + + private List idResponses; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdRequest.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdRequest.java new file mode 100644 index 00000000000..cc3ac543675 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdRequest.java @@ -0,0 +1,63 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) <2015> eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ +package org.egov.hrms.web.contract; + +import javax.validation.constraints.NotNull; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class IdRequest { + + @NotNull + private String idName; + + @NotNull + private String tenantId; + + private String format; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdResponse.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdResponse.java new file mode 100644 index 00000000000..ac167a59ddd --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdResponse.java @@ -0,0 +1,57 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) <2015> eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ +package org.egov.hrms.web.contract; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +@AllArgsConstructor +@NoArgsConstructor +public class IdResponse { + + private String id; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/RequestInfoWrapper.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/RequestInfoWrapper.java new file mode 100644 index 00000000000..ada1794cd4f --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/RequestInfoWrapper.java @@ -0,0 +1,64 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.web.contract; + +import javax.validation.constraints.NotNull; + +import org.egov.common.contract.request.RequestInfo; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RequestInfoWrapper { + + @NotNull + @JsonProperty("RequestInfo") + private RequestInfo requestInfo; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/User.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/User.java new file mode 100644 index 00000000000..b0a004a6ae9 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/User.java @@ -0,0 +1,186 @@ +package org.egov.hrms.web.contract; + +import java.util.List; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.egov.hrms.model.Role; +import org.egov.hrms.model.enums.GuardianRelation; +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Validated +@AllArgsConstructor +@EqualsAndHashCode +@Getter +@NoArgsConstructor +@Setter +@ToString +@Builder +@JsonIgnoreProperties( + ignoreUnknown = true +) +public class User { + + @JsonProperty("id") + private Long id; + + @Size(max=64) + @JsonProperty("uuid") + private String uuid; + + @Size(max=64) + @JsonProperty("userServiceUuid") + private String userServiceUuid; + + @Size(max=180) + @JsonProperty("userName") + private String userName; + + @Size(max=64) + @JsonProperty("password") + private String password; + + @Size(max = 5) + @JsonProperty("salutation") + private String salutation; + + @NotNull + @Size(max=250) + @JsonProperty("name") + private String name; + + @JsonProperty("gender") + private String gender; + + @Pattern(regexp = "^[0-9]{9,10}$", message = "MobileNumber should be either 9 or 10 digit number") + @JsonProperty("mobileNumber") + private String mobileNumber; + + @Size(max=128) + @JsonProperty("emailId") + private String emailId; + + @Size(max=50) + @JsonProperty("altContactNumber") + private String altContactNumber; + + @Size(max=10) + @JsonProperty("pan") + private String pan; + + @Pattern(regexp = "^[0-9]{12}$", message = "AdharNumber should be 12 digit number") + @JsonProperty("aadhaarNumber") + private String aadhaarNumber; + + @Size(max=300) + @JsonProperty("permanentAddress") + private String permanentAddress; + + @Size(max=300) + @JsonProperty("permanentCity") + private String permanentCity; + + @Size(max=10) + @JsonProperty("permanentPinCode") + private String permanentPincode; + + @Size(max=300) + @JsonProperty("correspondenceCity") + private String correspondenceCity; + + @Size(max=10) + @JsonProperty("correspondencePinCode") + private String correspondencePincode; + + @Size(max=300) + @JsonProperty("correspondenceAddress") + private String correspondenceAddress; + + @JsonProperty("active") + private Boolean active; + + @NotNull + @JsonProperty("dob") + private Long dob; + + @JsonProperty("pwdExpiryDate") + private Long pwdExpiryDate; + + @Size(max=16) + @JsonProperty("locale") + private String locale; + + @Size(max=50) + @JsonProperty("type") + private String type; + + @Size(max=36) + @JsonProperty("signature") + private String signature; + + @JsonProperty("accountLocked") + private Boolean accountLocked; + + @JsonProperty("roles") + @Valid + private List roles; + + @Size(max=100) + @JsonProperty("fatherOrHusbandName") + private String fatherOrHusbandName; + + @JsonProperty("relationship") + private GuardianRelation relationship; + + @Size(max=32) + @JsonProperty("bloodGroup") + private String bloodGroup; + + @Size(max=300) + @JsonProperty("identificationMark") + private String identificationMark; + + @Size(max=36) + @JsonProperty("photo") + private String photo; + + @Size(max=64) + @JsonProperty("createdBy") + private String createdBy; + + @JsonProperty("createdDate") + private Long createdDate; + + @Size(max=64) + @JsonProperty("lastModifiedBy") + private String lastModifiedBy; + + @JsonProperty("lastModifiedDate") + private Long lastModifiedDate; + + @JsonProperty("otpReference") + private String otpReference; + + @Size(max=256) + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("rowVersion") + private Integer rowVersion; + + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/UserRequest.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/UserRequest.java new file mode 100644 index 00000000000..699dc079614 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/UserRequest.java @@ -0,0 +1,74 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.web.contract; + +import javax.validation.constraints.NotNull; + +import org.egov.common.contract.request.RequestInfo; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@AllArgsConstructor +@EqualsAndHashCode +@Getter +@NoArgsConstructor +@Setter +@ToString +@Builder +public class UserRequest { + + @NotNull + @JsonProperty("RequestInfo") + private RequestInfo requestInfo; + + @NotNull + @JsonProperty("User") + private User user; + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/UserResponse.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/UserResponse.java new file mode 100644 index 00000000000..285964a0a87 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/UserResponse.java @@ -0,0 +1,69 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.web.contract; + +import java.util.ArrayList; +import java.util.List; + +import lombok.Builder; +import org.egov.common.contract.response.ResponseInfo; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@AllArgsConstructor +@EqualsAndHashCode +@Getter +@NoArgsConstructor +@Setter +@ToString +@Builder +public class UserResponse { + + private ResponseInfo responseInfo; + + private List user = new ArrayList(); + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/controller/EmployeeController.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/controller/EmployeeController.java new file mode 100644 index 00000000000..c15f77a19f0 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/controller/EmployeeController.java @@ -0,0 +1,134 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.web.controller; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.hrms.service.EmployeeService; +import org.egov.hrms.web.contract.EmployeeRequest; +import org.egov.hrms.web.contract.EmployeeResponse; +import org.egov.hrms.web.contract.EmployeeSearchCriteria; +import org.egov.hrms.web.contract.RequestInfoWrapper; +import org.egov.hrms.web.validator.EmployeeValidator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@RestController +@RequestMapping("/employees") +public class EmployeeController { + + @Autowired + private EmployeeService employeeService; + + @Autowired + private EmployeeValidator validator; + + + /** + * Maps Post Requests for _create & returns ResponseEntity of either + * EmployeeResponse type or ErrorResponse type + * + * @param employeeRequest + * @param bindingResult + * @return ResponseEntity + */ + @PostMapping(value = "/_create") + @ResponseBody + public ResponseEntity create(@RequestBody @Valid EmployeeRequest employeeRequest) { + validator.validateCreateEmployee(employeeRequest); + EmployeeResponse employeeResponse = employeeService.create(employeeRequest); + return new ResponseEntity<>(employeeResponse, HttpStatus.ACCEPTED); + } + + + /** + * Maps Post Requests for _update & returns ResponseEntity of either + * EmployeeResponse type or ErrorResponse type + * + * @param employeeRequest + * @return ResponseEntity + */ + @PostMapping(value = "/_update") + @ResponseBody + public ResponseEntity update(@RequestBody @Valid EmployeeRequest employeeRequest) { + validator.validateUpdateEmployee(employeeRequest); + EmployeeResponse employeeResponse = employeeService.update(employeeRequest); + return new ResponseEntity<>(employeeResponse, HttpStatus.ACCEPTED); + } + + + /** + * Maps Post Requests for _search & returns ResponseEntity of either + * EmployeeResponse type or ErrorResponse type + * + * @param criteria + * @param bindingResult + * @return ResponseEntity + */ + @PostMapping(value = "/_search") + @ResponseBody + public ResponseEntity search(@RequestBody @Valid RequestInfoWrapper requestInfoWrapper, @ModelAttribute @Valid EmployeeSearchCriteria criteria) { + validator.validateSearchRequest(requestInfoWrapper.getRequestInfo(), criteria); + log.info(criteria.toString()); + EmployeeResponse employeeResponse = employeeService.search(criteria, requestInfoWrapper.getRequestInfo()); + return new ResponseEntity<>(employeeResponse,HttpStatus.OK); + } + + @PostMapping("_count") + @ResponseBody + private ResponseEntity count(@RequestParam("tenantId") String tenantId, @RequestBody RequestInfo requestInfo) { + + Map response = new HashMap<>(); + validator.validateEmployeeCountRequest(tenantId); + response = employeeService.getEmployeeCountResponse(requestInfo,tenantId); + return new ResponseEntity<>(response,HttpStatus.OK); + } + + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/EgovOfflineSearchModel.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/EgovOfflineSearchModel.java new file mode 100644 index 00000000000..e744771def2 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/EgovOfflineSearchModel.java @@ -0,0 +1,20 @@ +package org.egov.hrms.web.models; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class EgovOfflineSearchModel extends EgovSearchModel { + @JsonProperty("clientReferenceId") + private List clientReferenceId = null; +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/EgovSearchModel.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/EgovSearchModel.java new file mode 100644 index 00000000000..ae080fbcc57 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/EgovSearchModel.java @@ -0,0 +1,22 @@ +package org.egov.hrms.web.models; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class EgovSearchModel { + @JsonProperty("id") + @Valid + private List id = null; +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/Exclude.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/Exclude.java new file mode 100644 index 00000000000..aa7eae18a57 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/Exclude.java @@ -0,0 +1,13 @@ +package org.egov.hrms.web.models; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +// This annotation is used to mark fields in a model class that should be ignored or excluded when the class is being processed, +// specifically during serialization to JSON or when constructing database queries. +public @interface Exclude { +} diff --git a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualSearch.java similarity index 54% rename from health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java rename to core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualSearch.java index 4de94e41839..dfae3a41092 100644 --- a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualSearch.java @@ -1,45 +1,37 @@ -package org.egov.individual.web.models; +package org.egov.hrms.web.models; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; +import javax.validation.Valid; +import javax.validation.constraints.DecimalMax; +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Exclude; +import lombok.experimental.SuperBuilder; import org.egov.common.models.individual.Gender; import org.egov.common.models.individual.Identifier; import org.egov.common.models.individual.Name; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import java.math.BigDecimal; -import java.util.Date; -import java.util.List; - /** * A representation of an Individual. */ - @ApiModel(description = "A representation of an Individual.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") - @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class IndividualSearch { - @JsonProperty("id") - private List id = null; - +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class IndividualSearch extends EgovOfflineSearchModel { @JsonProperty("individualId") - private String individualId = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; + private List individualId = null; @JsonProperty("name") @Valid @@ -54,7 +46,7 @@ public class IndividualSearch { private Gender gender = null; @JsonProperty("mobileNumber") - private String mobileNumber = null; + private List mobileNumber = null; @JsonProperty("socialCategory") @Exclude @@ -64,6 +56,7 @@ public class IndividualSearch { @Exclude private String wardCode = null; + //Exclude annotation to exclude the field during dynamic sql query generation, because this field is not available in table and generic query fails @JsonProperty("individualName") @Exclude private String individualName = null; @@ -84,5 +77,46 @@ public class IndividualSearch { @JsonProperty("boundaryCode") @Exclude private String boundaryCode = null; + + @JsonProperty("roleCodes") + @Exclude + private List roleCodes = null; + + @JsonProperty("username") + @Exclude + private List username; + + @JsonProperty("userId") + @Exclude + private List userId; + + @JsonProperty("userUuid") + @Exclude + @Size(min = 1) + private List userUuid; + + @JsonProperty("type") + private String type; + + @Exclude + @JsonProperty("latitude") + @DecimalMin("-90") + @DecimalMax("90") + private Double latitude; + + @Exclude + @JsonProperty("longitude") + @DecimalMin("-180") + @DecimalMax("180") + private Double longitude; + + /* + * @value unit of measurement in Kilometer + * */ + @Exclude + @JsonProperty("searchRadius") + @DecimalMin("0") + private Double searchRadius; + } diff --git a/health-services/stock/src/main/java/org/egov/stock/web/models/StockSearchRequest.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualSearchRequest.java similarity index 70% rename from health-services/stock/src/main/java/org/egov/stock/web/models/StockSearchRequest.java rename to core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualSearchRequest.java index b1eeec0dabb..dd968c97f25 100644 --- a/health-services/stock/src/main/java/org/egov/stock/web/models/StockSearchRequest.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualSearchRequest.java @@ -1,37 +1,37 @@ -package org.egov.stock.web.models; +package org.egov.hrms.web.models; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - /** -* StockSearchRequest +* IndividualSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class StockSearchRequest { - +public class IndividualSearchRequest { @JsonProperty("RequestInfo") @NotNull @Valid private org.egov.common.contract.request.RequestInfo requestInfo = null; - @JsonProperty("Stock") + @JsonProperty("Individual") @NotNull @Valid - private StockSearch stock = null; + private IndividualSearch individual = null; + + } diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/Boundary.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/Boundary.java new file mode 100644 index 00000000000..4972888a0fc --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/Boundary.java @@ -0,0 +1,44 @@ +package org.egov.hrms.web.models.boundary; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.hrms.model.AuditDetails; +import org.springframework.validation.annotation.Validated; + +/** + * Boundary + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Boundary { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("code") + @NotNull + private String code = null; + + @JsonProperty("geometry") + @Valid + private JsonNode geometry = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("additionalDetails") + private JsonNode additionalDetails = null; +} diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectSearchRequest.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundaryRequest.java similarity index 63% rename from health-services/project/src/main/java/org/egov/project/web/models/ProjectSearchRequest.java rename to core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundaryRequest.java index a0dbf1c361c..a9f4c40be39 100644 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectSearchRequest.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundaryRequest.java @@ -1,6 +1,10 @@ -package org.egov.project.web.models; +package org.egov.hrms.web.models.boundary; + +import java.util.List; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; @@ -9,31 +13,25 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - /** -* ProjectSearchRequest -*/ + * BoundaryRequest + */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") @Data -@NoArgsConstructor @AllArgsConstructor +@NoArgsConstructor @Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectSearchRequest { +public class BoundaryRequest { @JsonProperty("RequestInfo") - @NotNull @Valid private RequestInfo requestInfo = null; - @JsonProperty("Project") - @NotNull @Valid - private ProjectSearch project = null; + @NotNull + @JsonProperty("Boundary") + @Size(min = 1, max = 300) + private List boundary = null; } - diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundaryResponse.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundaryResponse.java new file mode 100644 index 00000000000..942e4b5f392 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundaryResponse.java @@ -0,0 +1,43 @@ +package org.egov.hrms.web.models.boundary; + +import java.util.ArrayList; +import java.util.List; +import javax.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryResponse + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Boundary") + @Valid + private List boundary = null; + + + public BoundaryResponse addBoundaryItem(Boundary boundaryItem) { + if (this.boundary == null) { + this.boundary = new ArrayList<>(); + } + this.boundary.add(boundaryItem); + return this; + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundarySearchCriteria.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundarySearchCriteria.java new file mode 100644 index 00000000000..6a9ccaf34dc --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundarySearchCriteria.java @@ -0,0 +1,37 @@ +package org.egov.hrms.web.models.boundary; + +import java.util.List; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundarySearchCriteria { + + @NotNull + @Size(min = 1) + @JsonProperty("codes") + private List codes; + + @NotNull + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/validator/EmployeeValidator.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/validator/EmployeeValidator.java new file mode 100644 index 00000000000..2a474e9d708 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/validator/EmployeeValidator.java @@ -0,0 +1,857 @@ +package org.egov.hrms.web.validator; + +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.request.Role; +import org.egov.hrms.config.PropertiesManager; +import org.egov.hrms.model.Assignment; +import org.egov.hrms.model.DeactivationDetails; +import org.egov.hrms.model.DepartmentalTest; +import org.egov.hrms.model.EducationalQualification; +import org.egov.hrms.model.Employee; +import org.egov.hrms.model.Jurisdiction; +import org.egov.hrms.model.ReactivationDetails; +import org.egov.hrms.model.ServiceHistory; +import org.egov.hrms.repository.RestCallRepository; +import org.egov.hrms.service.EmployeeService; +import org.egov.hrms.service.MDMSService; +import org.egov.hrms.service.UserService; +import org.egov.hrms.utils.ErrorConstants; +import org.egov.hrms.utils.HRMSConstants; +import org.egov.hrms.utils.HRMSUtils; +import org.egov.hrms.web.contract.EmployeeRequest; +import org.egov.hrms.web.contract.EmployeeResponse; +import org.egov.hrms.web.contract.EmployeeSearchCriteria; +import org.egov.hrms.web.contract.UserResponse; +import org.egov.hrms.web.models.boundary.BoundaryResponse; +import org.egov.mdms.model.MdmsResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import static org.egov.hrms.utils.ErrorConstants.CITIZEN_TYPE_CODE; + +@Service +@Slf4j +public class EmployeeValidator { + + @Autowired + private MDMSService mdmsService; + + @Autowired + private EmployeeService employeeService; + + @Autowired + private UserService userService; + + @Autowired + private PropertiesManager propertiesManager; + + @Autowired + private HRMSUtils hrmsUtils; + + @Autowired + private RestCallRepository restCallRepository; + + /** + * Validates employee request for create. Validations include: + * 1. Validating MDMS codes + * 2. Performing data sanity checks + * + * @param request + */ + public void validateCreateEmployee(EmployeeRequest request) { + Map errorMap = new HashMap<>(); + validateExistingDuplicates(request ,errorMap); + validatePassword(request, errorMap); + if(!CollectionUtils.isEmpty(errorMap.keySet())) + throw new CustomException(errorMap); + Map> boundaryMap = getBoundaryList(request.getRequestInfo(),request.getEmployees().get(0)); + //FIXME hierarchy type has to be validated + Map> mdmsData = mdmsService.getMDMSData(request.getRequestInfo(), request.getEmployees().get(0).getTenantId()); + if(!CollectionUtils.isEmpty(mdmsData.keySet())){ + request.getEmployees().stream().forEach(employee -> validateMdmsData(employee, errorMap, mdmsData,boundaryMap)); + } + if(!CollectionUtils.isEmpty(errorMap.keySet())) + throw new CustomException(errorMap); + } + + private void validatePassword(EmployeeRequest request, Map errorMap) { + List employees = request.getEmployees(); + if (!propertiesManager.isAutoGeneratePassword()) { + employees.forEach(employee -> { + if (StringUtils.isEmpty(employee.getUser().getPassword())) + errorMap.put(ErrorConstants.HRMS_PASSWORD_REQUIRED, ErrorConstants.HRMS_PASSWORD_REQUIRED_MSG); + }); + } + } + + public Map> getBoundaryList(RequestInfo requestInfo,Employee employee){ + List boundarytList = new ArrayList<>(); + Map> eachMasterMap = new HashMap<>(); + Map> masterData = new HashMap<>(); + if(!CollectionUtils.isEmpty(employee.getJurisdictions())){ + for(Jurisdiction jurisdiction: employee.getJurisdictions()){ + if(!boundarytList.contains(jurisdiction.getBoundary())) + boundarytList.add(jurisdiction.getBoundary()); + } + if(CollectionUtils.isEmpty(boundarytList)) + boundarytList.add(employee.getTenantId()); + } + + List boundaryResponseList = new ArrayList<>(); +// for(String boundary: boundarytList){ +// MdmsResponse responseLoc = mdmsService.fetchMDMSDataLoc(requestInfo, boundary); +// BoundaryResponse boundarySearchResponse = serviceRequestClient.fetchResult( +// new StringBuilder(propertiesManager.getBoundaryServiceHost() +// + propertiesManager.getBoundarySearchUrl() +// +"?limit=" + boundaries.size() +// + "&offset=0&tenantId=" + tenantId +// + "&codes=" + String.join(",", boundaries)), +// request.getRequestInfo(), +// BoundaryResponse.class +// ); +// if(!CollectionUtils.isEmpty(responseLoc.getMdmsRes())) +// boundaryResponseList.add(responseLoc); +// } + + if(!CollectionUtils.isEmpty(boundarytList)) { + try { + BoundaryResponse boundarySearchResponse = restCallRepository.fetchResult( + new StringBuilder(propertiesManager.getBoundaryServiceHost() + + propertiesManager.getBoundarySearchUrl() + +"?limit=" + boundarytList.size() + + "&offset=0&tenantId=" + employee.getTenantId() + + "&codes=" + String.join(",", boundarytList)), + requestInfo, + BoundaryResponse.class + ); + masterData.put(HRMSConstants.HRMS_MDMS_TENANT_BOUNDARY_CODE, boundarySearchResponse.getBoundary().stream() + .map(boundary -> boundary.getCode()) + .collect(Collectors.toList()) + ); + log.info("successfully fetch boundary"); + } catch (Exception e) { + log.error("error while fetching boundary"); + log.error("Error while fetching boundaries from Boundary Service", e); + throw new CustomException("BOUNDARY_SERVICE_SEARCH_ERROR","Error while fetching boundaries from Boundary Service : " + e.getMessage()); + } + } + + return masterData; + } + + /** + * Validates search request. Checks the following: + * 1. If a user who doesn't have access to open search is making an open search call. + * + * @param requestInfo + * @param criteria + */ + public void validateSearchRequest(RequestInfo requestInfo, EmployeeSearchCriteria criteria) { + Map errorMap = new HashMap<>(); + + if(requestInfo.getUserInfo() != null && requestInfo.getUserInfo().getType().equalsIgnoreCase(CITIZEN_TYPE_CODE) && !CollectionUtils.isEmpty(criteria.getIds())) + errorMap.put(ErrorConstants.HRMS_INVALID_SEARCH_CITIZEN_CODE, ErrorConstants.HRMS_INVALID_SEARCH_CITIZEN_MSG); + + if(criteria.isCriteriaEmpty(criteria)) { + String[] roles = propertiesManager.getOpenSearchEnabledRoles().split(","); + List reqroles = requestInfo.getUserInfo().getRoles().stream().map(Role::getCode).collect(Collectors.toList()); + boolean check = false; + for(String role : reqroles) { + if(Arrays.asList(roles).contains(role)) { + check = true; + break; + } + } + if(!check) { + errorMap.put(ErrorConstants.HRMS_INVALID_SEARCH_REQ_CODE, ErrorConstants.HRMS_INVALID_SEARCH_REQ_MSG); + } + } + if(null != criteria.getAsOnDate()) { + if(CollectionUtils.isEmpty(criteria.getDepartments()) || CollectionUtils.isEmpty(criteria.getDesignations())) + errorMap.put(ErrorConstants.HRMS_INVALID_SEARCH_AOD_CODE, ErrorConstants.HRMS_INVALID_SEARCH_AOD_MSG); + } + + if(!CollectionUtils.isEmpty( criteria.getRoles()) && StringUtils.isEmpty(criteria.getTenantId())) { + errorMap.put(ErrorConstants.HRMS_INVALID_SEARCH_ROLES_CODE, ErrorConstants.HRMS_INVALID_SEARCH_ROLES_MSG); + } + + if((!StringUtils.isEmpty(criteria.getPhone()) || !CollectionUtils.isEmpty(criteria.getNames())) && + StringUtils.isEmpty(criteria.getTenantId())) { + errorMap.put(ErrorConstants.HRMS_INVALID_SEARCH_USER_CODE, ErrorConstants.HRMS_INVALID_SEARCH_USER_MSG); + } + if(!CollectionUtils.isEmpty(errorMap.keySet())) + throw new CustomException(errorMap); + } + + /** + * Checks if the employee being created is duplicate with the following: + * 1. Validating mobile number + * 2. Validating username + * + * @param request + * @param errorMap + */ + private void validateExistingDuplicates(EmployeeRequest request, Map errorMap) { + List employees = request.getEmployees(); + validateDataUniqueness(employees,errorMap); + validateUserMobile(employees,errorMap,request.getRequestInfo()); + validateUserName(employees,errorMap,request.getRequestInfo()); + } + + /** + * Checks duplicate occurance of mobileNumber and code for bulk request + * + * @param employees + * @param errorMap + */ + private void validateDataUniqueness(List employees, Map errorMap) { + HashSet < String> codes = new HashSet<>(); + employees.forEach(employee -> { + if(null != employee.getCode()){ + if (codes.contains(employee.getCode())) + errorMap.put(ErrorConstants.HRMS_BULK_CREATE_DUPLICATE_EMPCODE_CODE,ErrorConstants.HRMS_BULK_CREATE_DUPLICATE_EMPCODE_MSG); + else + codes.add(employee.getCode()); + } + }); + } + + /** + * Checks if the mobile number used in the request is duplicate. + * + * @param employees + * @param errorMap + * @param requestInfo + */ + private void validateUserMobile(List employees, Map errorMap, RequestInfo requestInfo) { + HashSet < String> mobileNos = new HashSet<>(); + employees.forEach(employee -> { + boolean autoGenerateMobileNumber = employee.getUser().getMobileNumber() == null || + employee.getUser().getMobileNumber().isEmpty(); + int maxRetryCount = 5; + if (autoGenerateMobileNumber) { + int retryCount = 0; + String generatedMobileNumber = hrmsUtils.generateMobileNumber(); + while ((retryCount < maxRetryCount) && mobileNos.contains(generatedMobileNumber)) { + generatedMobileNumber = hrmsUtils.generateMobileNumber(); + retryCount++; + } + employee.getUser().setMobileNumber(generatedMobileNumber); + } + if(mobileNos.contains(employee.getUser().getMobileNumber())) + errorMap.put(ErrorConstants.HRMS_BULK_CREATE_DUPLICATE_MOBILE_CODE, ErrorConstants.HRMS_BULK_CREATE_DUPLICATE_MOBILE_MSG ); + else + mobileNos.add(employee.getUser().getMobileNumber()); + Map userSearchCriteria = new HashMap<>(); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE, HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID,employee.getTenantId()); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_MOBILENO,employee.getUser().getMobileNumber()); + UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + if (autoGenerateMobileNumber && !CollectionUtils.isEmpty(userResponse.getUser())) { + int retryCount = 0; + String generatedMobileNumber = hrmsUtils.generateMobileNumber(); + while ((retryCount < maxRetryCount) && !CollectionUtils.isEmpty(userResponse.getUser())) { + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_MOBILENO,generatedMobileNumber); + userResponse = userService.getUser(requestInfo, userSearchCriteria); + retryCount++; + } + employee.getUser().setMobileNumber(generatedMobileNumber); + } + if(!CollectionUtils.isEmpty(userResponse.getUser())){ + errorMap.put(ErrorConstants.HRMS_USER_EXIST_MOB_CODE, + ErrorConstants.HRMS_USER_EXIST_MOB_MSG); + } + }); + } + + /** + * Checks if the username is duplicate + * + * @param employees + * @param errorMap + * @param requestInfo + */ + private void validateUserName(List employees, Map errorMap, RequestInfo requestInfo) { + employees.forEach(employee -> { + if(!StringUtils.isEmpty(employee.getCode())){ + Map userSearchCriteria = new HashMap<>(); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE, HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID,employee.getTenantId()); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_USERNAME,employee.getCode()); + UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + if(!CollectionUtils.isEmpty(userResponse.getUser())){ + errorMap.put(ErrorConstants.HRMS_USER_EXIST_USERNAME_CODE, + ErrorConstants.HRMS_USER_EXIST_USERNAME_MSG); + } + } + }); + } + + /** + * Validates MDMS codes of the request. + * + * @param employee + * @param errorMap + * @param mdmsData + */ + private void validateMdmsData(Employee employee, Map errorMap, Map> mdmsData, Map> boundaryMap) { + validateEmployee(employee, errorMap, mdmsData); + validateAssignments(employee, errorMap, mdmsData); + validateServiceHistory(employee, errorMap, mdmsData); +// validateJurisdicton(employee, errorMap, mdmsData, boundaryMap); + validateEducationalDetails(employee, errorMap, mdmsData); + validateDepartmentalTest(employee, errorMap, mdmsData); + } + + + /** + * Performs checks for maintaining data consistency + * @param employee + * @param errorMap + * @param mdmsData + * @param existingEmp + * @param requestInfo + */ + public void validateDataConsistency(Employee employee, Map errorMap, Map> mdmsData, Employee existingEmp, RequestInfo requestInfo) { + validateUserData(existingEmp,employee,errorMap, requestInfo); + validateConsistencyAssignment(existingEmp,employee,errorMap); + validateConsistencyJurisdiction(existingEmp,employee,errorMap); + validateConsistencyDepartmentalTest(existingEmp,employee,errorMap); + validateConsistencyEducationalDetails(existingEmp,employee,errorMap); + validateConsistencyServiceHistory(existingEmp, employee, errorMap); + validateConsistencyEmployeeDocument(existingEmp, employee, errorMap); + validateConsistencyDeactivationDetails(existingEmp, employee, errorMap); + if(!employee.getIsActive()) + validateDeactivationDetails(existingEmp, employee, errorMap, mdmsData); + if(employee.getIsActive() && employee.getReActivateEmployee()) + validateReactivationDetails(existingEmp, employee, errorMap, mdmsData); + } + + /** + * Check whether employee code has changed + * @param existingEmp + * @param employee + * @param errorMap + * @param requestInfo + */ + private void validateUserData(Employee existingEmp, Employee employee, Map errorMap, RequestInfo requestInfo) { + if(!employee.getCode().equals(existingEmp.getCode())) + errorMap.put(ErrorConstants.HRMS_UPDATE_EMPLOYEE_CODE_CHANGE_CODE,ErrorConstants.HRMS_UPDATE_EMPLOYEE_CODE_CHANGE_MSG); + if(!employee.getUser().getMobileNumber().equals(existingEmp.getUser().getMobileNumber())){ + Map userSearchCriteria = new HashMap<>(); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE, HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID,employee.getTenantId()); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_MOBILENO,employee.getUser().getMobileNumber()); + UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + if(!CollectionUtils.isEmpty(userResponse.getUser())){ + if(!employee.getUser().getUuid().equals(userResponse.getUser().get(0).getUuid())){ + errorMap.put(ErrorConstants.HRMS_UPDATE_EXISTING_MOBNO_CODE,ErrorConstants.HRMS_UPDATE_EXISTING_MOBNO_MSG); + } + } + + + } + + } + + /** + * Checks the following: + * 1. Whether the mobile number is valid + * 2. Whether the roles are valid + * 3. Whether the employee status mentioned is valid. + * 4. Whether the employee type mentioned is valid + * 5. Whether the date of appointment of the employee is valid. + * + * @param employee + * @param errorMap + * @param mdmsData + */ + private void validateEmployee(Employee employee, Map errorMap, Map> mdmsData) { + + if(employee.getUser().getMobileNumber().length() != 10 && employee.getUser().getMobileNumber().length() != 9) { + errorMap.put(ErrorConstants.HRMS_INVALID_MOB_NO_CODE, ErrorConstants.HRMS_INVALID_MOB_NO_MSG); + } + + if(CollectionUtils.isEmpty(employee.getUser().getRoles())) + errorMap.put(ErrorConstants.HRMS_MISSING_ROLES_CODE, ErrorConstants.HRMS_INVALID_ROLES_MSG); + else { + for(org.egov.hrms.model.Role role: employee.getUser().getRoles()) { + if(!mdmsData.get(HRMSConstants.HRMS_MDMS_ROLES_CODE).contains(role.getCode())) + errorMap.put(ErrorConstants.HRMS_INVALID_ROLE_CODE, ErrorConstants.HRMS_INVALID_ROLE_MSG ); + } + } + /*if(!mdmsData.get(HRMSConstants.HRMS_MDMS_EMP_STATUS_CODE).contains(employee.getEmployeeStatus())) + errorMap.put(ErrorConstants.HRMS_INVALID_EMP_STATUS_CODE, ErrorConstants.HRMS_INVALID_EMP_STATUS_MSG);*/ + if(!mdmsData.get(HRMSConstants.HRMS_MDMS_EMP_TYPE_CODE).contains(employee.getEmployeeType())) + errorMap.put(ErrorConstants.HRMS_INVALID_EMP_TYPE_CODE, ErrorConstants.HRMS_INVALID_EMP_TYPE_MSG); + if(null != employee.getDateOfAppointment() && employee.getDateOfAppointment() > new Date().getTime()) + errorMap.put(ErrorConstants.HRMS_INVALID_DATE_OF_APPOINTMENT_CODE, ErrorConstants.HRMS_INVALID_DATE_OF_APPOINTMENT_MSG); + if(null != employee.getUser().getDob()) { + if(employee.getUser().getDob() >= new Date().getTime()) + errorMap.put(ErrorConstants.HRMS_INVALID_DOB_CODE, ErrorConstants.HRMS_INVALID_DOB_MSG); + if(null != employee.getDateOfAppointment() && employee.getDateOfAppointment() < employee.getUser().getDob()) + errorMap.put(ErrorConstants.HRMS_INVALID_DATE_OF_APPOINTMENT_DOB_CODE, ErrorConstants.HRMS_INVALID_DATE_OF_APPOINTMENT_DOB_MSG); + } + } + + /** + * Checks the following: + * 1. If there is more than one current assignment. + * 2. if period of assignment of any of the assignments overlap with that of others. + * 3. if the Department code is valid + * 4. If the Designation code is valid + * 5. If the assignment dates are valid + * + * @param employee + * @param errorMap + * @param mdmsData + */ + private void validateAssignments(Employee employee, Map errorMap, Map> mdmsData) { + if (employee.getAssignments() != null && !employee.getAssignments().isEmpty()) { + List currentAssignments = employee.getAssignments().stream().filter(assignment -> assignment.getIsCurrentAssignment()).collect(Collectors.toList()); + if (currentAssignments.size() != 1) { + errorMap.put(ErrorConstants.HRMS_INVALID_CURRENT_ASSGN_CODE, ErrorConstants.HRMS_INVALID_CURRENT_ASSGN_MSG); + } + employee.getAssignments().sort(new Comparator() { + @Override + public int compare(Assignment assignment1, Assignment assignment2) { + return assignment1.getFromDate().compareTo(assignment2.getFromDate()); + } + }); + int length = employee.getAssignments().size(); + boolean overlappingCheck = false; + for (int i = 0; i < length - 1; i++) { + if (null != employee.getAssignments().get(i).getToDate() && employee.getAssignments().get(i).getToDate() > employee.getAssignments().get(i + 1).getFromDate()) + overlappingCheck = true; + } + if (overlappingCheck) + errorMap.put(ErrorConstants.HRMS_OVERLAPPING_ASSGN_CODE, ErrorConstants.HRMS_OVERLAPPING_ASSGN_MSG); + + for (Assignment assignment : employee.getAssignments()) { + if (!assignment.getIsCurrentAssignment() && !CollectionUtils.isEmpty(currentAssignments) && null != assignment.getToDate() && currentAssignments.get(0).getFromDate() < assignment.getToDate()) + errorMap.put(ErrorConstants.HRMS_OVERLAPPING_ASSGN_CURRENT_CODE, ErrorConstants.HRMS_OVERLAPPING_ASSGN_CURRENT_MSG); + if (!mdmsData.get(HRMSConstants.HRMS_MDMS_DEPT_CODE).contains(assignment.getDepartment())) + errorMap.put(ErrorConstants.HRMS_INVALID_DEPT_CODE, ErrorConstants.HRMS_INVALID_DEPT_MSG); + /*if (!assignment.getDesignation().equalsIgnoreCase("undefined") && + !mdmsData.get(HRMSConstants.HRMS_MDMS_DESG_CODE).contains(assignment.getDesignation())) + errorMap.put(ErrorConstants.HRMS_INVALID_DESG_CODE, ErrorConstants.HRMS_INVALID_DESG_MSG);*/ + if (assignment.getIsCurrentAssignment() && null != assignment.getToDate()) + errorMap.put(ErrorConstants.HRMS_INVALID_ASSIGNMENT_CURRENT_TO_DATE_CODE, ErrorConstants.HRMS_INVALID_ASSIGNMENT_CURRENT_TO_DATE_MSG); + if (!assignment.getIsCurrentAssignment() && null == assignment.getToDate()) + errorMap.put(ErrorConstants.HRMS_INVALID_ASSIGNMENT_NON_CURRENT_TO_DATE_CODE, ErrorConstants.HRMS_INVALID_ASSIGNMENT_NON_CURRENT_TO_DATE_MSG); + if (null != assignment.getToDate() && assignment.getFromDate() > assignment.getToDate()) + errorMap.put(ErrorConstants.HRMS_INVALID_ASSIGNMENT_PERIOD_CODE, ErrorConstants.HRMS_INVALID_ASSIGNMENT_PERIOD_MSG); + if (employee.getUser().getDob() != null) + if (assignment.getFromDate() < employee.getUser().getDob() || (null != assignment.getToDate() && assignment.getToDate() < employee.getUser().getDob())) + errorMap.put(ErrorConstants.HRMS_INVALID_ASSIGNMENT_DATES_CODE, ErrorConstants.HRMS_INVALID_ASSIGNMENT_DATES_MSG); + if (null != employee.getDateOfAppointment() && assignment.getFromDate() < employee.getDateOfAppointment()) + errorMap.put(ErrorConstants.HRMS_INVALID_ASSIGNMENT_DATES_APPOINTMENT_CODE, ErrorConstants.HRMS_INVALID_ASSIGNMENT_DATES_APPOINTMENT_MSG); + + } + } + + } + + /** + * Checks the follwing: + * 1. If the status of service is valid. + * 2. If the service period is valid. + * 3. If the service dates is valid. + * 4. If there is more than 1 current Positions. + * 5. If service end date is null for current position + * + * @param employee + * @param errorMap + * @param mdmsData + */ + private void validateServiceHistory(Employee employee, Map errorMap, Map> mdmsData) { + if(!CollectionUtils.isEmpty(employee.getServiceHistory())){ + List currentService = employee.getServiceHistory().stream().filter(serviceHistory -> null!= serviceHistory.getIsCurrentPosition() && serviceHistory.getIsCurrentPosition()).collect(Collectors.toList()); + if(currentService.size() > 1){ + errorMap.put(ErrorConstants.HRMS_INVALID_CURRENT_SERVICE_CODE, ErrorConstants.HRMS_INVALID_CURRENT_SERVICE_MSG); + } + for(ServiceHistory history: employee.getServiceHistory()) { + if( (null== history.getIsCurrentPosition() || !history.getIsCurrentPosition()) && !CollectionUtils.isEmpty(currentService) && null != currentService.get(0).getServiceFrom() && null != history.getServiceTo() && currentService.get(0).getServiceFrom() new Date().getTime()) || (null != history.getServiceTo() && history.getServiceTo() > new Date().getTime()) + || (null != history.getServiceFrom() && null != history.getServiceTo() && history.getServiceFrom() > history.getServiceTo())) + errorMap.put(ErrorConstants.HRMS_INVALID_SERVICE_PERIOD_CODE, ErrorConstants.HRMS_INVALID_SERVICE_PERIOD_MSG); + if(employee.getUser().getDob()!=null ) + if((null != history.getServiceFrom() && history.getServiceFrom() < employee.getUser().getDob()) || (null != history.getServiceTo() && history.getServiceTo() < employee.getUser().getDob())) + errorMap.put(ErrorConstants.HRMS_INVALID_SERVICE_DATES_CODE, ErrorConstants.HRMS_INVALID_SERVICE_DATES_MSG); + } + } + } + + /** + * Checks the following: + * 1. If the qualification is valid. + * 2. If the specialization provided is valid. + * 3. If the year of passing is valid. + * + * @param employee + * @param errorMap + * @param mdmsData + */ + private void validateEducationalDetails(Employee employee, Map errorMap, Map> mdmsData) { + if(!CollectionUtils.isEmpty(employee.getEducation())){ + for(EducationalQualification education : employee.getEducation()) { + if(null!= education.getQualification() && !mdmsData.get(HRMSConstants.HRMS_MDMS_QUALIFICATION_CODE).contains(education.getQualification())) + errorMap.put(ErrorConstants.HRMS_INVALID_QUALIFICATION_CODE, ErrorConstants.HRMS_INVALID_QUALIFICATION_MSG); + if(null != education.getStream() && !mdmsData.get(HRMSConstants.HRMS_MDMS_STREAMS_CODE).contains(education.getStream())) + errorMap.put(ErrorConstants.HRMS_INVALID_EDUCATIONAL_STREAM_CODE, ErrorConstants.HRMS_INVALID_EDUCATIONAL_STREAM_MSG); + if(null != education.getYearOfPassing() && education.getYearOfPassing() > new Date().getTime()){ + errorMap.put(ErrorConstants.HRMS_INVALID_EDUCATIONAL_PASSING_YEAR_CODE, ErrorConstants.HRMS_INVALID_EDUCATIONAL_PASSING_YEAR_MSG); + } + } + } + } + + /** + * 1. Checks if there is atleast 1 active jurisdiction + * 2. If hierarchy is valid + * 3. If boundaryType is valid + * 4. If boundary is valid + * + * @param employee + * @param errorMap + * @param mdmsData + */ + private void validateJurisdicton(Employee employee, Map errorMap, Map> mdmsData,Map> boundaryMap) { + if(CollectionUtils.isEmpty(employee.getJurisdictions().stream().filter(jurisdiction -> null == jurisdiction.getIsActive() || jurisdiction.getIsActive() && jurisdiction.getIsActive() ).collect(Collectors.toList()))){ + errorMap.put(ErrorConstants.HRMS_INVALID_JURISDICTION_ACTIIEV_NULL_CODE,ErrorConstants.HRMS_INVALID_JURISDICTION_ACTIIEV_NULL_MSG); + } + for(Jurisdiction jurisdiction: employee.getJurisdictions()) { + String hierarchy_type_path = String.format(HRMSConstants.HRMS_TENANTBOUNDARY_HIERARCHY_JSONPATH,jurisdiction.getBoundary()); + String boundary_type_path = String.format(HRMSConstants.HRMS_TENANTBOUNDARY_BOUNDARY_TYPE_JSONPATH,jurisdiction.getHierarchy(),jurisdiction.getBoundary()); + String boundary_value_path = String.format(HRMSConstants.HRMS_TENANTBOUNDARY_BOUNDARY_VALUE_JSONPATH,jurisdiction.getHierarchy(),jurisdiction.getBoundary()); + List hierarchyTypes = JsonPath.read(boundaryMap,hierarchy_type_path); + List boundaryTypes = JsonPath.read(boundaryMap,boundary_type_path); + List boundaryValues = JsonPath.read(boundaryMap,boundary_value_path); + if(!hierarchyTypes.contains(jurisdiction.getHierarchy())) + errorMap.put(ErrorConstants.HRMS_INVALID_JURISDICTION_HEIRARCHY_CODE, ErrorConstants.HRMS_INVALID_JURISDICTION_HEIRARCHY_MSG); + if(!boundaryTypes.contains(jurisdiction.getBoundaryType())) + errorMap.put(ErrorConstants.HRMS_INVALID_JURISDICTION_BOUNDARY_TYPE_CODE, ErrorConstants.HRMS_INVALID_JURISDICTION_BOUNDARY_TYPE_MSG); + if(!boundaryValues.contains(jurisdiction.getBoundary())) + errorMap.put(ErrorConstants.HRMS_INVALID_JURISDICTION_BOUNDARY_CODE, ErrorConstants.HRMS_INVALID_JURISDICTION_BOUNDARY_MSG); + } + + + } + + + /** + * Checks the follwing: + * 1. If the dept test is valid. + * 2. If the year of passing is valid. + * + * @param employee + * @param errorMap + * @param mdmsData + */ + private void validateDepartmentalTest(Employee employee, Map errorMap, Map> mdmsData) { + if(!CollectionUtils.isEmpty(employee.getTests())) { + for (DepartmentalTest test : employee.getTests()) { + if (null!=test.getTest() && !mdmsData.get(HRMSConstants.HRMS_MDMS_DEPT_TEST_CODE).contains(test.getTest())) + errorMap.put(ErrorConstants.HRMS_INVALID_DEPARTMENTAL_TEST_CODE, ErrorConstants.HRMS_INVALID_DEPARTMENTAL_TEST_MSG ); + if (null!= test.getYearOfPassing() && test.getYearOfPassing() > new Date().getTime()) { + errorMap.put(ErrorConstants.HRMS_INVALID_DEPARTMENTAL_TEST_PASSING_YEAR_CODE, ErrorConstants.HRMS_INVALID_DEPARTMENTAL_TEST_PASSING_YEAR_MSG); + } + + } + } + } + + /** + * Validates if the deactivation details are provided every time an employee is deactivated. + * @param existingEmp + * @param updatedEmployeeData + * @param errorMap + * @param mdmsData + */ + private void validateDeactivationDetails(Employee existingEmp, Employee updatedEmployeeData, Map errorMap, Map> mdmsData){ + if(!CollectionUtils.isEmpty(updatedEmployeeData.getDeactivationDetails())) { + Date date = new Date(); + Date currentDateStartTime = Date.from(date.toInstant().atZone(ZoneId.systemDefault()) + .truncatedTo(ChronoUnit.DAYS).toInstant()); + for (DeactivationDetails deactivationDetails : updatedEmployeeData.getDeactivationDetails()) { + if (deactivationDetails.getId()==null){ + if(updatedEmployeeData.getIsActive()){ + errorMap.put(ErrorConstants.HRMS_INVALID_DEACT_REQUEST_CODE, ErrorConstants.HRMS_INVALID_DEACT_REQUEST_MSG); + } + } + if(deactivationDetails.getEffectiveFrom() > new Date().getTime()) + errorMap.put(ErrorConstants.HRMS_UPDATE_DEACT_DETAILS_INCORRECT_EFFECTIVEFROM_CODE, ErrorConstants.HRMS_UPDATE_DEACT_DETAILS_INCORRECT_EFFECTIVEFROM_MSG); + + if(deactivationDetails.getEffectiveFrom() < currentDateStartTime.getTime()) + errorMap.put(ErrorConstants.HRMS_UPDATE_DEACT_DETAILS_INCORRECT_EFFECTIVEFROM_CODE, ErrorConstants.HRMS_UPDATE_DEACT_DETAILS_INCORRECT_EFFECTIVEFROM_MSG); + + if (! mdmsData.get(HRMSConstants.HRMS_MDMS_DEACT_REASON_CODE).contains(deactivationDetails.getReasonForDeactivation())) + errorMap.put(ErrorConstants.HRMS_INVALID_DEACT_REASON_CODE, ErrorConstants.HRMS_INVALID_DEACT_REASON_MSG); + } + } + } + + private void validateReactivationDetails(Employee existingEmp, Employee updatedEmployeeData, Map errorMap, Map> mdmsData){ + if(!CollectionUtils.isEmpty(updatedEmployeeData.getReactivationDetails())) { + for (ReactivationDetails reactivationDetails : updatedEmployeeData.getReactivationDetails()) { + Boolean isValidDetails = existingEmp.getDeactivationDetails().get(0).getEffectiveFrom() <= reactivationDetails.getEffectiveFrom() + && reactivationDetails.getEffectiveFrom() <= new Date().getTime(); + if(!isValidDetails) + errorMap.put(ErrorConstants.HRMS_UPDATE_REACT_DETAILS_INCORRECT_EFFECTIVEFROM_CODE, ErrorConstants.HRMS_UPDATE_REACT_DETAILS_INCORRECT_EFFECTIVEFROM_MSG); + + } + } + } + + /** + * Validates the employee request for update. Validates the following: + * 1. MDMS codes in the request + * 2. Performs data consistency checks. + * + * @param request + */ + public void validateUpdateEmployee(EmployeeRequest request) { + Map errorMap = new HashMap<>(); + Map> boundaryMap = getBoundaryList(request.getRequestInfo(),request.getEmployees().get(0)); + Map> mdmsData = mdmsService.getMDMSData(request.getRequestInfo(), request.getEmployees().get(0).getTenantId()); + List uuidList = request.getEmployees().stream().map(Employee :: getUuid).collect(Collectors.toList()); + EmployeeResponse existingEmployeeResponse = employeeService.search(EmployeeSearchCriteria.builder().uuids(uuidList) + .tenantId(request.getEmployees().get(0).getTenantId()) + .build(),request.getRequestInfo()); + List existingEmployees = existingEmployeeResponse.getEmployees(); + for(Employee employee: request.getEmployees()){ + if(validateEmployeeForUpdate(employee, errorMap)){ + if(!existingEmployees.isEmpty()){ + Employee existingEmp = existingEmployees.stream().filter(existingEmployee -> existingEmployee.getUuid().equals(employee.getUuid())).findFirst().get(); + validateDataConsistency(employee, errorMap, mdmsData, existingEmp, request.getRequestInfo()); + } + else + errorMap.put(ErrorConstants.HRMS_UPDATE_EMPLOYEE_NOT_EXIST_CODE, ErrorConstants.HRMS_UPDATE_EMPLOYEE_NOT_EXIST_MSG); + } + validateMdmsData(employee, errorMap, mdmsData,boundaryMap); + } + if(!CollectionUtils.isEmpty(errorMap.keySet())) { + throw new CustomException(errorMap); + } + + + } + + /** + * Checks if the ID, UUID and Code are present in the update request + * + * @param employee + * @param errorMap + * @return + */ + private boolean validateEmployeeForUpdate(Employee employee, Map errorMap) { + boolean isvalid = true; + if(employee.getId() == null){ + errorMap.put(ErrorConstants.HRMS_UPDATE_NULL_ID_CODE, ErrorConstants.HRMS_UPDATE_NULL_ID_MSG); + isvalid=false; + } + if(StringUtils.isEmpty(employee.getCode())){ + errorMap.put(ErrorConstants.HRMS_UPDATE_NULL_CODE_CODE, ErrorConstants.HRMS_UPDATE_NULL_CODE_MSG); + isvalid=false; + } + if(StringUtils.isEmpty(employee.getUuid())){ + errorMap.put(ErrorConstants.HRMS_UPDATE_NULL_UUID_CODE, ErrorConstants.HRMS_UPDATE_NULL_UUID_MSG); + isvalid=false; + } + + return isvalid; + + } + + /** + * Juridictions once created in the system cannot be deleted, they can however be changed. Validates that condition + * + * @param existingEmp + * @param updatedEmployeeData + * @param errorMap + */ + private void validateConsistencyJurisdiction(Employee existingEmp, Employee updatedEmployeeData, Map errorMap) { + boolean check = + updatedEmployeeData.getJurisdictions().stream() + .map(jurisdiction -> jurisdiction.getId()) + .collect(Collectors.toList()) + .containsAll(existingEmp.getJurisdictions().stream() + .map(jurisdiction -> jurisdiction.getId()) + .collect(Collectors.toList())); + if(!check){ + errorMap.put(ErrorConstants.HRMS_UPDATE_JURISDICTION_INCOSISTENT_CODE, ErrorConstants.HRMS_UPDATE_JURISDICTION_INCOSISTENT_MSG); + } + + } + + /** + * Assignments once created in the system cannot be deleted, they can however be changed. Validates that condition + * + * @param existingEmp + * @param updatedEmployeeData + * @param errorMap + */ + private void validateConsistencyAssignment(Employee existingEmp, Employee updatedEmployeeData, Map errorMap) { + if (updatedEmployeeData.getAssignments() != null && existingEmp.getAssignments() != null) { + boolean check = + updatedEmployeeData.getAssignments().stream() + .map(assignment -> assignment.getId()) + .collect(Collectors.toList()) + .containsAll(existingEmp.getAssignments().stream() + .map(assignment -> assignment.getId()) + .collect(Collectors.toList())); + if (!check) { + errorMap.put(ErrorConstants.HRMS_UPDATE_ASSIGNEMENT_INCOSISTENT_CODE, ErrorConstants.HRMS_UPDATE_ASSIGNEMENT_INCOSISTENT_MSG); + } + } + } + + /** + * Dept Test details once created in the system cannot be deleted, they can however be changed. Validates that condition + * @param existingEmp + * @param updatedEmployeeData + * @param errorMap + */ + private void validateConsistencyDepartmentalTest(Employee existingEmp, Employee updatedEmployeeData, Map errorMap){ + if(!CollectionUtils.isEmpty(updatedEmployeeData.getTests())){ + boolean check = + updatedEmployeeData.getTests().stream() + .map(test -> test.getId()) + .collect(Collectors.toList()) + .containsAll(existingEmp.getTests().stream() + .map(test -> test.getId()) + .collect(Collectors.toList())); + if(!check){ + errorMap.put(ErrorConstants.HRMS_UPDATE_TESTS_INCOSISTENT_CODE, ErrorConstants.HRMS_UPDATE_TESTS_INCOSISTENT_MSG); + } + } + + } + + /** + * Education Details once created in the system cannot be deleted, they can however be changed. Validates that condition + * + * @param existingEmp + * @param updatedEmployeeData + * @param errorMap + */ + private void validateConsistencyEducationalDetails(Employee existingEmp, Employee updatedEmployeeData, Map errorMap){ + if(!CollectionUtils.isEmpty(updatedEmployeeData.getEducation())){ + boolean check = + updatedEmployeeData.getEducation().stream() + .map(educationalQualification -> educationalQualification.getId()) + .collect(Collectors.toList()) + .containsAll(existingEmp.getEducation().stream() + .map(educationalQualification -> educationalQualification.getId()) + .collect(Collectors.toList())); + if(!check){ + errorMap.put(ErrorConstants.HRMS_UPDATE_EDUCATION_INCOSISTENT_CODE, ErrorConstants.HRMS_UPDATE_EDUCATION_INCOSISTENT_MSG); + } + } + } + + /** + * Service History once created in the system cannot be deleted, they can however be changed. Validates that condition + * + * @param existingEmp + * @param updatedEmployeeData + * @param errorMap + */ + private void validateConsistencyServiceHistory(Employee existingEmp, Employee updatedEmployeeData, Map errorMap){ + if(!CollectionUtils.isEmpty(updatedEmployeeData.getServiceHistory())){ + boolean check = + updatedEmployeeData.getServiceHistory().stream() + .map(serviceHistory -> serviceHistory.getId()) + .collect(Collectors.toList()) + .containsAll(existingEmp.getServiceHistory().stream() + .map(serviceHistory -> serviceHistory.getId()) + .collect(Collectors.toList())); + if(!check){ + errorMap.put(ErrorConstants.HRMS_UPDATE_SERVICE_HISTORY_INCOSISTENT_CODE, ErrorConstants.HRMS_UPDATE_SERVICE_HISTORY_INCOSISTENT_MSG); + } + + } + + } + + /** + * Documents once created in the system cannot be deleted, they can however be changed. Validates that condition + * + * @param existingEmp + * @param updatedEmployeeData + * @param errorMap + */ + private void validateConsistencyEmployeeDocument(Employee existingEmp, Employee updatedEmployeeData, Map errorMap){ + if(!CollectionUtils.isEmpty(updatedEmployeeData.getDocuments())){ + boolean check = + updatedEmployeeData.getDocuments().stream() + .map(employeeDocument -> employeeDocument.getId()) + .collect(Collectors.toList()) + .containsAll(existingEmp.getDocuments().stream() + .map(employeeDocument -> employeeDocument.getId()) + .collect(Collectors.toList())); + if (!check) { + errorMap.put(ErrorConstants.HRMS_UPDATE_DOCUMENT_INCOSISTENT_CODE, ErrorConstants.HRMS_UPDATE_DOCUMENT_INCOSISTENT_MSG); + } + } + + } + + /** + * Deactivation Details once created in the system cannot be deleted, they can however be changed. Validates that condition + * + * @param existingEmp + * @param updatedEmployeeData + * @param errorMap + */ + private void validateConsistencyDeactivationDetails(Employee existingEmp, Employee updatedEmployeeData, Map errorMap){ + if(!CollectionUtils.isEmpty(updatedEmployeeData.getDeactivationDetails())){ + boolean check = + updatedEmployeeData.getDeactivationDetails().stream() + .map(deactivationDetails -> deactivationDetails.getId()) + .collect(Collectors.toList()) + .containsAll(existingEmp.getDeactivationDetails().stream() + .map(employeeDocument -> employeeDocument.getId()) + .collect(Collectors.toList())); + if (!check) { + errorMap.put(ErrorConstants.HRMS_UPDATE_DEACT_DETAILS_INCOSISTENT_CODE, ErrorConstants.HRMS_UPDATE_DEACT_DETAILS_INCOSISTENT_MSG); + } + } + + } + + public void validateEmployeeCountRequest(String tenantId){ + Map errorMap = new HashMap<>(); + if(StringUtils.isEmpty(tenantId)) + errorMap.put(ErrorConstants.HRMS_EMPLOYEE_COUNT_ERROR_CODE, ErrorConstants.HRMS_EMPLOYEE_COUNT_ERROR_MSG); + + if(!CollectionUtils.isEmpty(errorMap.keySet())) { + throw new CustomException(errorMap); + } + } + +} diff --git a/core-services/egov-hrms/src/main/resources/application.properties b/core-services/egov-hrms/src/main/resources/application.properties new file mode 100644 index 00000000000..dcece925352 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/application.properties @@ -0,0 +1,123 @@ +#---------------------------- DATABASE CONFIGURATIONS -----------------------------# +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/egov_hrms +spring.datasource.username=postgres +spring.datasource.password=postgres + +#----------------------------- FLYWAY CONFIGURATIONS ------------------------------# +spring.flyway.url=jdbc:postgresql://localhost:5432/egov_hrms +spring.flyway.user=postgres +spring.flyway.password=postgres +#spring.flyway.table=hr_employee_schema_version +spring.flyway.baseline-on-migrate=true +spring.flyway.outOfOrder=true +spring.flyway.locations=classpath:/db/migration/main,db/migration/seed +spring.flyway.enabled=true + +#--------------------------- PATH & PORT CONFIGURATIONS ---------------------------# +server.contextPath=/egov-hrms +server.servlet.context-path=/egov-hrms +server.port=9999 + +#---------------------------- TIMEZONE CONFIGURATIONS -----------------------------# +app.timezone=UTC + +#-------------------------- EXTERNAL API CONFIGURATIONS ---------------------------# + + +egov.services.data_sync_employee.required = false + + +#mdms urls +egov.mdms.host=https://dev.digit.org +egov.mdms.search.endpoint=/egov-mdms-service/v1/_search +#egov.mdms.search.endpoint=/egov-mdms-service-test/v1/_search + +#filestore urls +egov.filestore.host=https://dev.digit.org +egov.filestore.url.endpoint=/filestore/v1/files/url + +#localization urls +egov.localization.host=https://dev.digit.org +egov.localization.search.endpoint=/localization/messages/v1/_search + +#egov-otp urls +egov.otp.host=http://egov-otp.egov:8080/ +egov.otp.create.endpoint=otp/v1/_create + +egov.environment.domain=https://dev.digit.org/ + +#user +egov.user.host=https://dev.digit.org +egov.user.search.endpoint=/user/v1/_search +egov.user.create.endpoint=/user/users/_createnovalidate +egov.user.update.endpoint=/user/users/_updatenovalidate + +#idgen configs +#egov.idgen.host=http://egov-idgen:8080/ +egov.idgen.host=https://dev.digit.org/ +egov.idgen.path=egov-idgen/id/_generate +egov.idgen.ack.name=hrms.employeecode +egov.idgen.ack.format=EMP-[city]-[SEQ_EG_HRMS_EMP_CODE] + + +egov.individual.host=https://health-dev.digit.org +egov.individual.create.endpoint=/individual/v1/_create +egov.individual.update.endpoint=/individual/v1/_update +egov.individual.search.endpoint=/individual/v1/_search + +# use qualifier as "defaultUserService" to integrate with egov-user module +# use qualifier as "individualService" to integrate with individual module +egov.hrms.user.service.qualifier=individualService + + +#user +egov.hrms.employee.app.link=https://mseva.lgpunjab.gov.in/employee/user/login + + +#CONFIGS +egov.hrms.default.pagination.limit=200 +egov.hrms.default.pwd.length=8 +open.search.enabled.roles=SUPERUSER +egov.pwd.allowed.special.characters=@#$% +parent.level.tenant.id=pb +decryption.abac.enable=false + +#------------------------------ KAFKA CONFIGURATIONS ------------------------------# +# KAFKA SERVER CONFIGURATIONS +spring.kafka.bootstrap.servers=localhost:9092 +spring.kafka.consumer.properties.spring.json.use.type.headers=false + +# SPRING KAFKA CONSUMER CONFIGURATIONS +spring.kafka.consumer.value-deserializer=org.egov.tracer.kafka.deserializer.HashMapDeserializer +spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer +spring.kafka.consumer.group-id=employee-group1 + +# SPRING KAFKA PRODUCER CONFIGURATIONS +spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer +spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer + +# KAFKA TOPIC CONFIGURATIONS +kafka.topics.save.service=save-hrms-employee +kafka.topics.update.service=update-hrms-employee +kafka.topics.notification.sms=egov.core.notification.sms +kafka.topics.hrms.updateData= egov-hrms-update + +spring.kafka.listener.missing-topics-fatal=false + +#------------------------------ TRACER CONFIGURATIONS -----------------------------# +# tracer.detailed.tracing.enabled=false + +#------------------------------ LOGGER CONFIGURATIONS -----------------------------# +logging.pattern.console=%clr(%X{CORRELATION_ID:-}) %clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx} + +log4j.logger.org.springframework.jdbc.core = TRACE + +state.level.tenant.id=default + +egov.hrms.auto.generate.password=true + +# BOUNDARY SERVICE +egov.boundary.host=http://localhost:8081 +egov.boundary.search.url=/boundary-service/boundary/_search +egov.boundary.hierarchy=HCM-Moz-Hierarchy \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/resources/config/application-config.properties b/core-services/egov-hrms/src/main/resources/config/application-config.properties new file mode 100644 index 00000000000..8ade6ea4997 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/config/application-config.properties @@ -0,0 +1,17 @@ +#----------------------- DEFAULT PAGINATION CONFIGURATIONS ------------------------# +egov.services.emp.search.pagesize.default=200 +egov.services.emp.search.pageno.max=50 +egov.services.emp.search.pagesize.max=500 + + +#------------------------- CODE & SEQUENCE CONFIGURATIONS -------------------------# + +# Already configured in ApplicationConfiguration file but right now not being used. Instead using enum. +egov.services.emp.seq.assignment=seq_egeis_assignment +egov.services.emp.seq.departmentaltest=seq_egeis_departmentaltest +egov.services.emp.seq.educationalqualification=seq_egeis_educationalqualification +egov.services.emp.seq.hoddepartment=seq_egeis_hoddepartment +egov.services.emp.seq.probation=seq_egeis_probation +egov.services.emp.seq.regularisation=seq_egeis_regularisation +egov.services.emp.seq.servicehistory=seq_egeis_servicehistory +egov.services.emp.seq.technicalqualification=seq_egeis_technicalqualification diff --git a/core-services/egov-hrms/src/main/resources/config/hrm-employee-update-persister.yml b/core-services/egov-hrms/src/main/resources/config/hrm-employee-update-persister.yml new file mode 100644 index 00000000000..1f57cc0719c --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/config/hrm-employee-update-persister.yml @@ -0,0 +1,265 @@ +serviceMaps: + serviceName: HRMS + mappings: + - version: 1.0 + name: hrms + description: Persists employee details in the table + fromTopic: update-hrms-employee + isTransaction: true + queryMaps: + + - query: DELETE from eg_hrms_employee WHERE uuid=? on + + basePath: Employees.* + jsonMaps: + + -jsonPath: $.Employees.*.uuid + + + + - query: INSERT INTO eg_hrms_employee(tenantid, id, uuid, code, phone, name, dateOfAppointment, employeestatus, employeetype, active, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.* + jsonMaps: + + + - jsonPath: $.Employees.*.tenantId + + - jsonPath: $.Employees.*.id + + - jsonPath: $.Employees.*.uuid + + - jsonPath: $.Employees.*.code + + - jsonPath: $.Employees.*.user.mobileNumber + + - jsonPath: $.Employees.*.user.name + + - jsonPath: $.Employees.*.dateOfAppointment + + - jsonPath: $.Employees.*.employeeStatus + + - jsonPath: $.Employees.*.employeeType + + - jsonPath: $.Employees.*.active + + - jsonPath: $.Employees.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.auditDetails.lastModifiedDate + + + + - query: INSERT INTO eg_hrms_assignment(tenantid, uuid, position, department, designation, fromdate, todate, govtordernumber, reportingto, isHOD, employeeid, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.assignments.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.assignments[*].id)].tenantId + + - jsonPath: $.Employees.*.assignments.*.id + + - jsonPath: $.Employees.*.assignments.*.position + + - jsonPath: $.Employees.*.assignments.*.department + + - jsonPath: $.Employees.*.assignments.*.designation + + - jsonPath: $.Employees.*.assignments.*.fromDate + + - jsonPath: $.Employees.*.assignments.*.toDate + + - jsonPath: $.Employees.*.assignments.*.govtOrderNumber + + - jsonPath: $.Employees.*.assignments.*.reportingTo + + - jsonPath: $.Employees.*.assignments.*.isHOD + + - jsonPath: $.Employees[*][?({id} in @.assignments[*].id)].uuid + + - jsonPath: $.Employees.*.assignments.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.assignments.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.assignments.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.assignments.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_educationaldetails(tenantid, uuid, employeeid, qualification, stream, yearofpassing, university, remarks, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.education.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.education[*].id)].tenantId + + - jsonPath: $.Employees.*.education.*.id + + - jsonPath: $.Employees[*][?({id} in @.education[*].id)].uuid + + - jsonPath: $.Employees.*.education.*.qualification + + - jsonPath: $.Employees.*.education.*.stream + + - jsonPath: $.Employees.*.education.*.yearOfPassing + + - jsonPath: $.Employees.*.education.*.university + + - jsonPath: $.Employees.*.education.*.remarks + + - jsonPath: $.Employees.*.education.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.education.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.education.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.education.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_departmentaltests(tenantid, uuid, employeeid, test, yearofpassing, remarks, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.tests.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.tests[*].id)].tenantId + + - jsonPath: $.Employees.*.tests.*.id + + - jsonPath: $.Employees[*][?({id} in @.tests[*].id)].uuid + + - jsonPath: $.Employees.*.tests.*.test + + - jsonPath: $.Employees.*.tests.*.yearOfPassing + + - jsonPath: $.Employees.*.tests.*.remarks + + - jsonPath: $.Employees.*.tests.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.tests.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.tests.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.tests.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_empdocuments(tenantid, uuid, employeeid, documentid, documentname, referencetype, referenceid, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.documents.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.documents[*].id)].tenantId + + - jsonPath: $.Employees.*.documents.*.id + + - jsonPath: $.Employees[*][?({id} in @.documents[*].id)].uuid + + - jsonPath: $.Employees.*.documents.*.documentId + + - jsonPath: $.Employees.*.documents.*.documentName + + - jsonPath: $.Employees.*.documents.*.referenceType + + - jsonPath: $.Employees.*.documents.*.referenceId + + - jsonPath: $.Employees.*.documents.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.documents.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.documents.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.documents.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_servicehistory(tenantid, uuid, employeeid, servicestatus, servicefrom, serviceto, ordernumber, isCurrentPosition, location, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.serviceHistory.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.serviceHistory[*].id)].tenantId + + - jsonPath: $.Employees.*.serviceHistory.*.id + + - jsonPath: $.Employees[*][?({id} in @.serviceHistory[*].id)].uuid + + - jsonPath: $.Employees.*.serviceHistory.*.serviceStatus + + - jsonPath: $.Employees.*.serviceHistory.*.serviceFrom + + - jsonPath: $.Employees.*.serviceHistory.*.serviceTo + + - jsonPath: $.Employees.*.serviceHistory.*.orderNo + + - jsonPath: $.Employees.*.serviceHistory.*.isCurrentPosition + + - jsonPath: $.Employees.*.serviceHistory.*.location + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.lastModifiedDate + + -query: INSERT INTO eg_hrms_jurisdiction (uuid, employeeid, hierarchy, boundarytype, boundary, tenantid, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.jurisdictions.* + jsonMaps: + + - jsonPath: $.Employees.*.jurisdictions.*.id + + - jsonPath: $.Employees[*][?({id} in @.jurisdictions[*].id)].uuid + + - jsonPath: $.Employees.*.jurisdictions.*.hierarchy + + - jsonPath: $.Employees.*.jurisdictions.*.boundaryType + + - jsonPath: $.Employees.*.jurisdictions.*.boundary + + - jsonPath: $.Employees[*][?({id} in @.jurisdictions[*].id)].tenantId + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.lastModifiedDate + + + + - query: INSERT INTO eg_hrms_deactivationdetails(uuid, employeeid, reasonfordeactivation, effectivefrom, ordernumber, typeOfDeactivation, tenantid, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.deactivationDetails.* + jsonMaps: + + - jsonPath: $.Employees.*.deactivationDetails.*.id + + - jsonPath: $.Employees[*][?({id} in @.deactivationDetails[*].id)].uuid + + - jsonPath: $.Employees.*.deactivationDetails.*.reasonForDeactivation + + - jsonPath: $.Employees.*.deactivationDetails.*.effectiveFrom + + - jsonPath: $.Employees.*.deactivationDetails.*.orderNo + + - jsonPath: $.Employees.*.deactivationDetails.*.typeOfDeactivation + + - jsonPath: $.Employees[*][?({id} in @.deactivationDetails[*].id)].tenantId + + - jsonPath: $.Employees.*.deactivationDetails.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.deactivationDetails.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.deactivationDetails.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.deactivationDetails.*.auditDetails.lastModifiedDate + diff --git a/core-services/egov-hrms/src/main/resources/config/hrms-employee-persister.yml b/core-services/egov-hrms/src/main/resources/config/hrms-employee-persister.yml new file mode 100644 index 00000000000..74dbd1940ef --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/config/hrms-employee-persister.yml @@ -0,0 +1,501 @@ +serviceMaps: + serviceName: HRMS + mappings: + - version: 1.0 + name: hrms + description: Persists employee details in the table + fromTopic: save-hrms-employee + isTransaction: true + queryMaps: + - query: INSERT INTO eg_hrms_employee(tenantid, id, uuid, code, dateOfAppointment, employeestatus, employeetype, active, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.* + jsonMaps: + + + - jsonPath: $.Employees.*.tenantId + + - jsonPath: $.Employees.*.id + + - jsonPath: $.Employees.*.uuid + + - jsonPath: $.Employees.*.code + + - jsonPath: $.Employees.*.dateOfAppointment + + - jsonPath: $.Employees.*.employeeStatus + + - jsonPath: $.Employees.*.employeeType + + - jsonPath: $.Employees.*.isActive + + - jsonPath: $.Employees.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.auditDetails.lastModifiedDate + + + + - query: INSERT INTO eg_hrms_assignment(tenantid, uuid, position, department, designation, fromdate, todate, govtordernumber, reportingto, isHOD, iscurrentassignment, employeeid, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.assignments.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.assignments[*].id)].tenantId + + - jsonPath: $.Employees.*.assignments.*.id + + - jsonPath: $.Employees.*.assignments.*.position + + - jsonPath: $.Employees.*.assignments.*.department + + - jsonPath: $.Employees.*.assignments.*.designation + + - jsonPath: $.Employees.*.assignments.*.fromDate + + - jsonPath: $.Employees.*.assignments.*.toDate + + - jsonPath: $.Employees.*.assignments.*.govtOrderNumber + + - jsonPath: $.Employees.*.assignments.*.reportingTo + + - jsonPath: $.Employees.*.assignments.*.isHOD + + - jsonPath: $.Employees.*.assignments.*.isCurrentAssignment + + - jsonPath: $.Employees[*][?({id} in @.assignments[*].id)].uuid + + - jsonPath: $.Employees.*.assignments.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.assignments.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.assignments.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.assignments.*.auditDetails.lastModifiedDate + + + + + - query: INSERT INTO eg_hrms_educationaldetails(tenantid, uuid, employeeid, qualification, stream, yearofpassing, university, remarks, isactive, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.education.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.education[*].id)].tenantId + + - jsonPath: $.Employees.*.education.*.id + + - jsonPath: $.Employees[*][?({id} in @.education[*].id)].uuid + + - jsonPath: $.Employees.*.education.*.qualification + + - jsonPath: $.Employees.*.education.*.stream + + - jsonPath: $.Employees.*.education.*.yearOfPassing + + - jsonPath: $.Employees.*.education.*.university + + - jsonPath: $.Employees.*.education.*.remarks + + - jsonPath: $.Employees.*.education.*.isActive + + - jsonPath: $.Employees.*.education.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.education.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.education.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.education.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_departmentaltests(tenantid, uuid, employeeid, test, yearofpassing, remarks, isactive, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.tests.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.tests[*].id)].tenantId + + - jsonPath: $.Employees.*.tests.*.id + + - jsonPath: $.Employees[*][?({id} in @.tests[*].id)].uuid + + - jsonPath: $.Employees.*.tests.*.test + + - jsonPath: $.Employees.*.tests.*.yearOfPassing + + - jsonPath: $.Employees.*.tests.*.remarks + + - jsonPath: $.Employees.*.tests.*.isActive + + - jsonPath: $.Employees.*.tests.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.tests.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.tests.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.tests.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_empdocuments(tenantid, uuid, employeeid, documentid, documentname, referencetype, referenceid, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.documents.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.documents[*].id)].tenantId + + - jsonPath: $.Employees.*.documents.*.id + + - jsonPath: $.Employees[*][?({id} in @.documents[*].id)].uuid + + - jsonPath: $.Employees.*.documents.*.documentId + + - jsonPath: $.Employees.*.documents.*.documentName + + - jsonPath: $.Employees.*.documents.*.referenceType + + - jsonPath: $.Employees.*.documents.*.referenceId + + - jsonPath: $.Employees.*.documents.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.documents.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.documents.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.documents.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_servicehistory(tenantid, uuid, employeeid, servicestatus, servicefrom, serviceto, ordernumber, isCurrentPosition, location, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.serviceHistory.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.serviceHistory[*].id)].tenantId + + - jsonPath: $.Employees.*.serviceHistory.*.id + + - jsonPath: $.Employees[*][?({id} in @.serviceHistory[*].id)].uuid + + - jsonPath: $.Employees.*.serviceHistory.*.serviceStatus + + - jsonPath: $.Employees.*.serviceHistory.*.serviceFrom + + - jsonPath: $.Employees.*.serviceHistory.*.serviceTo + + - jsonPath: $.Employees.*.serviceHistory.*.orderNo + + - jsonPath: $.Employees.*.serviceHistory.*.isCurrentPosition + + - jsonPath: $.Employees.*.serviceHistory.*.location + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_jurisdiction (uuid, employeeid, hierarchy, boundarytype, boundary, tenantid, isActive, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.jurisdictions.* + jsonMaps: + + - jsonPath: $.Employees.*.jurisdictions.*.id + + - jsonPath: $.Employees[*][?({id} in @.jurisdictions[*].id)].uuid + + - jsonPath: $.Employees.*.jurisdictions.*.hierarchy + + - jsonPath: $.Employees.*.jurisdictions.*.boundaryType + + - jsonPath: $.Employees.*.jurisdictions.*.boundary + + - jsonPath: $.Employees[*][?({id} in @.jurisdictions[*].id)].tenantId + + - jsonPath: $.Employees.*.jurisdictions.*.isActive + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.lastModifiedDate + + + + + - version: 1.0 + name: hrms + description: Persists employee details in the table + fromTopic: update-hrms-employee + isTransaction: true + queryMaps: + - query: DELETE from eg_hrms_employee WHERE uuid=? + + basePath: Employees.* + jsonMaps: + + - jsonPath: $.Employees.*.uuid + + - query: INSERT INTO eg_hrms_employee(tenantid, id, uuid, code, dateOfAppointment, employeestatus, employeetype, active, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.* + jsonMaps: + + + - jsonPath: $.Employees.*.tenantId + + - jsonPath: $.Employees.*.id + + - jsonPath: $.Employees.*.uuid + + - jsonPath: $.Employees.*.code + + - jsonPath: $.Employees.*.dateOfAppointment + + - jsonPath: $.Employees.*.employeeStatus + + - jsonPath: $.Employees.*.employeeType + + - jsonPath: $.Employees.*.isActive + + - jsonPath: $.Employees.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.auditDetails.lastModifiedDate + + + + - query: INSERT INTO eg_hrms_assignment(tenantid, uuid, position, department, designation, fromdate, todate, govtordernumber, reportingto, isHOD, iscurrentassignment, employeeid, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.assignments.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.assignments[*].id)].tenantId + + - jsonPath: $.Employees.*.assignments.*.id + + - jsonPath: $.Employees.*.assignments.*.position + + - jsonPath: $.Employees.*.assignments.*.department + + - jsonPath: $.Employees.*.assignments.*.designation + + - jsonPath: $.Employees.*.assignments.*.fromDate + + - jsonPath: $.Employees.*.assignments.*.toDate + + - jsonPath: $.Employees.*.assignments.*.govtOrderNumber + + - jsonPath: $.Employees.*.assignments.*.reportingTo + + - jsonPath: $.Employees.*.assignments.*.isHOD + + - jsonPath: $.Employees.*.assignments.*.isCurrentAssignment + + - jsonPath: $.Employees[*][?({id} in @.assignments[*].id)].uuid + + - jsonPath: $.Employees.*.assignments.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.assignments.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.assignments.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.assignments.*.auditDetails.lastModifiedDate + + + + + - query: INSERT INTO eg_hrms_educationaldetails(tenantid, uuid, employeeid, qualification, stream, yearofpassing, university, remarks, isactive, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.education.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.education[*].id)].tenantId + + - jsonPath: $.Employees.*.education.*.id + + - jsonPath: $.Employees[*][?({id} in @.education[*].id)].uuid + + - jsonPath: $.Employees.*.education.*.qualification + + - jsonPath: $.Employees.*.education.*.stream + + - jsonPath: $.Employees.*.education.*.yearOfPassing + + - jsonPath: $.Employees.*.education.*.university + + - jsonPath: $.Employees.*.education.*.remarks + + - jsonPath: $.Employees.*.education.*.isActive + + - jsonPath: $.Employees.*.education.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.education.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.education.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.education.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_departmentaltests(tenantid, uuid, employeeid, test, yearofpassing, remarks, isactive, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.tests.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.tests[*].id)].tenantId + + - jsonPath: $.Employees.*.tests.*.id + + - jsonPath: $.Employees[*][?({id} in @.tests[*].id)].uuid + + - jsonPath: $.Employees.*.tests.*.test + + - jsonPath: $.Employees.*.tests.*.yearOfPassing + + - jsonPath: $.Employees.*.tests.*.remarks + + - jsonPath: $.Employees.*.tests.*.isActive + + - jsonPath: $.Employees.*.tests.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.tests.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.tests.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.tests.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_empdocuments(tenantid, uuid, employeeid, documentid, documentname, referencetype, referenceid, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.documents.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.documents[*].id)].tenantId + + - jsonPath: $.Employees.*.documents.*.id + + - jsonPath: $.Employees[*][?({id} in @.documents[*].id)].uuid + + - jsonPath: $.Employees.*.documents.*.documentId + + - jsonPath: $.Employees.*.documents.*.documentName + + - jsonPath: $.Employees.*.documents.*.referenceType + + - jsonPath: $.Employees.*.documents.*.referenceId + + - jsonPath: $.Employees.*.documents.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.documents.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.documents.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.documents.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_servicehistory(tenantid, uuid, employeeid, servicestatus, servicefrom, serviceto, ordernumber, isCurrentPosition, location, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.serviceHistory.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.serviceHistory[*].id)].tenantId + + - jsonPath: $.Employees.*.serviceHistory.*.id + + - jsonPath: $.Employees[*][?({id} in @.serviceHistory[*].id)].uuid + + - jsonPath: $.Employees.*.serviceHistory.*.serviceStatus + + - jsonPath: $.Employees.*.serviceHistory.*.serviceFrom + + - jsonPath: $.Employees.*.serviceHistory.*.serviceTo + + - jsonPath: $.Employees.*.serviceHistory.*.orderNo + + - jsonPath: $.Employees.*.serviceHistory.*.isCurrentPosition + + - jsonPath: $.Employees.*.serviceHistory.*.location + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_jurisdiction (uuid, employeeid, hierarchy, boundarytype, boundary, tenantid, isActive, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.jurisdictions.* + jsonMaps: + + - jsonPath: $.Employees.*.jurisdictions.*.id + + - jsonPath: $.Employees[*][?({id} in @.jurisdictions[*].id)].uuid + + - jsonPath: $.Employees.*.jurisdictions.*.hierarchy + + - jsonPath: $.Employees.*.jurisdictions.*.boundaryType + + - jsonPath: $.Employees.*.jurisdictions.*.boundary + + - jsonPath: $.Employees[*][?({id} in @.jurisdictions[*].id)].tenantId + + - jsonPath: $.Employees.*.jurisdictions.*.isActive + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.lastModifiedDate + + + + - query: INSERT INTO eg_hrms_deactivationdetails(uuid, employeeid, reasonfordeactivation, effectivefrom, ordernumber, remarks, tenantid, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.deactivationDetails.* + jsonMaps: + + - jsonPath: $.Employees.*.deactivationDetails.*.id + + - jsonPath: $.Employees[*][?({id} in @.deactivationDetails[*].id)].uuid + + - jsonPath: $.Employees.*.deactivationDetails.*.reasonForDeactivation + + - jsonPath: $.Employees.*.deactivationDetails.*.effectiveFrom + + - jsonPath: $.Employees.*.deactivationDetails.*.orderNo + + - jsonPath: $.Employees.*.deactivationDetails.*.remarks + + - jsonPath: $.Employees[*][?({id} in @.deactivationDetails[*].id)].tenantId + + - jsonPath: $.Employees.*.deactivationDetails.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.deactivationDetails.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.deactivationDetails.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.deactivationDetails.*.auditDetails.lastModifiedDate diff --git a/core-services/egov-hrms/src/main/resources/db/Dockerfile b/core-services/egov-hrms/src/main/resources/db/Dockerfile new file mode 100644 index 00000000000..e7da01d7f0b --- /dev/null +++ b/core-services/egov-hrms/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"] \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/resources/db/migrate.sh b/core-services/egov-hrms/src/main/resources/db/migrate.sh new file mode 100644 index 00000000000..f9d6617822c --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migrate.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS -baselineOnMigrate=true -outOfOrder=true migrate diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20190122152236__create_hrms_employee_table_ddl.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190122152236__create_hrms_employee_table_ddl.sql new file mode 100644 index 00000000000..ea38846f3b3 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190122152236__create_hrms_employee_table_ddl.sql @@ -0,0 +1,159 @@ +CREATE TABLE eg_hrms_employee ( + id BIGINT NOT NULL, + uuid CHARACTER VARYING(1024) NOT NULL, + code CHARACTER VARYING(250), + phone CHARACTER VARYING(250), + name CHARACTER VARYING(250), + dateOfAppointment BIGINT, + employeestatus CHARACTER VARYING(250), + employeetype CHARACTER VARYING(250), + active BOOLEAN, + tenantid CHARACTER VARYING(250) NOT NULL, + createdby CHARACTER VARYING(250) NOT NULL, + createddate BIGINT NOT NULL, + lastmodifiedby CHARACTER VARYING(250), + lastModifiedDate BIGINT, + + CONSTRAINT pk_eghrms_employee PRIMARY KEY (uuid), + CONSTRAINT uk_eghrms_employee_code UNIQUE (code) +); + + + +CREATE TABLE eg_hrms_assignment ( + uuid CHARACTER VARYING(1024) NOT NULL, + employeeid CHARACTER VARYING(1024) NOT NULL, + position BIGINT, + department CHARACTER VARYING(250), + designation CHARACTER VARYING(250), + fromdate BIGINT, + todate BIGINT, + govtordernumber CHARACTER VARYING(250), + reportingto CHARACTER VARYING(250), + isHOD BOOLEAN, + tenantid CHARACTER VARYING(250) NOT NULL, + createdby CHARACTER VARYING(250) NOT NULL, + createddate BIGINT NOT NULL, + lastmodifiedby CHARACTER VARYING(250), + lastModifiedDate BIGINT, + + CONSTRAINT pk_eghrms_assignment PRIMARY KEY (uuid), + CONSTRAINT ck_eghrms_employee_fromTo CHECK (fromdate <= todate), + CONSTRAINT fk_eghrms_assignment_employeeid FOREIGN KEY (employeeid) REFERENCES eg_hrms_employee (uuid) ON DELETE CASCADE + +); + + +CREATE TABLE eg_hrms_educationaldetails ( + uuid CHARACTER VARYING(1024) NOT NULL, + employeeid CHARACTER VARYING(1024) NOT NULL, + qualification CHARACTER VARYING(250), + stream CHARACTER VARYING(250), + yearofpassing BIGINT, + university CHARACTER VARYING(250), + remarks CHARACTER VARYING(250), + tenantid CHARACTER VARYING(250) NOT NULL, + createdby CHARACTER VARYING(250) NOT NULL, + createddate BIGINT NOT NULL, + lastmodifiedby CHARACTER VARYING(250), + lastModifiedDate BIGINT, + + CONSTRAINT pk_eghrms_educationaldetails PRIMARY KEY (uuid), + CONSTRAINT fk_eghrms_educationaldetails_employeeid FOREIGN KEY (employeeid) REFERENCES eg_hrms_employee (uuid) ON DELETE CASCADE + +); + + +CREATE TABLE eg_hrms_departmentaltests ( + uuid CHARACTER VARYING(1024) NOT NULL, + employeeid CHARACTER VARYING(1024) NOT NULL, + test CHARACTER VARYING(250), + yearofpassing BIGINT, + remarks CHARACTER VARYING(250), + tenantid CHARACTER VARYING(250) NOT NULL, + createdby CHARACTER VARYING(250) NOT NULL, + createddate BIGINT NOT NULL, + lastmodifiedby CHARACTER VARYING(250), + lastModifiedDate BIGINT, + + CONSTRAINT pk_eghrms_departmentaltests PRIMARY KEY (uuid), + CONSTRAINT fk_eghrms_departmentaltests_employeeid FOREIGN KEY (employeeid) REFERENCES eg_hrms_employee (uuid) ON DELETE CASCADE + +); + + +CREATE TABLE eg_hrms_empdocuments ( + uuid CHARACTER VARYING(1024) NOT NULL, + employeeid CHARACTER VARYING(1024) NOT NULL, + documentid CHARACTER VARYING(250) NOT NULL, + documentname CHARACTER VARYING(250), + referencetype CHARACTER VARYING(250), + referenceid CHARACTER VARYING(250) NOT NULL, + tenantid CHARACTER VARYING(250) NOT NULL, + createdby CHARACTER VARYING(250) NOT NULL, + createddate BIGINT NOT NULL, + lastmodifiedby CHARACTER VARYING(250), + lastModifiedDate BIGINT, + + CONSTRAINT pk_eghrms_empdocuments PRIMARY KEY (uuid), + CONSTRAINT fk_eghrms_empdocuments_employeeid FOREIGN KEY (employeeid) REFERENCES eg_hrms_employee (uuid) ON DELETE CASCADE + +); + + +CREATE TABLE eg_hrms_servicehistory ( + uuid CHARACTER VARYING(1024) NOT NULL, + employeeid CHARACTER VARYING(1024) NOT NULL, + servicestatus CHARACTER VARYING(250), + servicefrom BIGINT, + serviceto BIGINT, + ordernumber CHARACTER VARYING(250), + isCurrentPosition BOOLEAN, + location CHARACTER VARYING(250), + tenantid CHARACTER VARYING(250) NOT NULL, + createdby CHARACTER VARYING(250) NOT NULL, + createddate BIGINT NOT NULL, + lastmodifiedby CHARACTER VARYING(250), + lastModifiedDate BIGINT, + + CONSTRAINT pk_eghrms_servicehistory PRIMARY KEY (uuid), + CONSTRAINT fk_eghrms_servicehistory_employeeid FOREIGN KEY (employeeid) REFERENCES eg_hrms_employee (uuid) ON DELETE CASCADE + +); + +CREATE TABLE eg_hrms_jurisdiction ( + uuid CHARACTER VARYING(1024) NOT NULL, + employeeid CHARACTER VARYING(1024) NOT NULL, + hierarchy CHARACTER VARYING(250) NOT NULL, + boundarytype CHARACTER VARYING(250) NOT NULL, + boundary CHARACTER VARYING(250) NOT NULL, + tenantid CHARACTER VARYING(250) NOT NULL, + createdby CHARACTER VARYING(250) NOT NULL, + createddate BIGINT NOT NULL, + lastmodifiedby CHARACTER VARYING(250), + lastModifiedDate BIGINT, + + CONSTRAINT pk_eghrms_jurisdiction PRIMARY KEY (uuid), + CONSTRAINT fk_eghrms_jurisdiction_employeeid FOREIGN KEY (employeeid) REFERENCES eg_hrms_employee (uuid) ON DELETE CASCADE + +); + +CREATE TABLE eg_hrms_deactivationdetails ( + uuid CHARACTER VARYING(1024) NOT NULL, + employeeid CHARACTER VARYING(1024) NOT NULL, + reasonfordeactivation CHARACTER VARYING(250), + effectivefrom BIGINT, + ordernumber CHARACTER VARYING(250), + typeOfDeactivation CHARACTER VARYING(250), + tenantid CHARACTER VARYING(250) NOT NULL, + createdby CHARACTER VARYING(250) NOT NULL, + createddate BIGINT NOT NULL, + lastmodifiedby CHARACTER VARYING(250), + lastModifiedDate BIGINT, + + CONSTRAINT pk_eghrms_deactivationdetails PRIMARY KEY (uuid), + CONSTRAINT fk_eghrms_deactivationdetails_employeeid FOREIGN KEY (employeeid) REFERENCES eg_hrms_employee (uuid) ON DELETE CASCADE + +); + + diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20190130120650__alter_assgnmt_add_currentassgmt_ddl.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190130120650__alter_assgnmt_add_currentassgmt_ddl.sql new file mode 100644 index 00000000000..cbf835475d0 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190130120650__alter_assgnmt_add_currentassgmt_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE eg_hrms_assignment ADD COLUMN iscurrentassignment BOOLEAN; \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20190204154948__create_position_sequence_ddl.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190204154948__create_position_sequence_ddl.sql new file mode 100644 index 00000000000..9cd94842b9c --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190204154948__create_position_sequence_ddl.sql @@ -0,0 +1 @@ +CREATE SEQUENCE EG_HRMS_POSITION; diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20190204163735__alter_deactivation_rename_remarks_ddl.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190204163735__alter_deactivation_rename_remarks_ddl.sql new file mode 100644 index 00000000000..48fa186edf2 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190204163735__alter_deactivation_rename_remarks_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE eg_hrms_deactivationdetails RENAME COLUMN typeOfDeactivation TO remarks; diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20190204172710__secondary_indexes_ddl.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190204172710__secondary_indexes_ddl.sql new file mode 100644 index 00000000000..ad6f5458476 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190204172710__secondary_indexes_ddl.sql @@ -0,0 +1,4 @@ +CREATE INDEX code_idx ON eg_hrms_employee ("code"); +CREATE INDEX dept_idx ON eg_hrms_assignment ("department"); +CREATE INDEX posn_idx ON eg_hrms_assignment ("position"); +CREATE INDEX desg_idx ON eg_hrms_assignment ("designation"); \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20190215120811__alter_uk_constraint_dml.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190215120811__alter_uk_constraint_dml.sql new file mode 100644 index 00000000000..06a6ebf8635 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190215120811__alter_uk_constraint_dml.sql @@ -0,0 +1,2 @@ +ALTER TABLE eg_hrms_employee DROP CONSTRAINT uk_eghrms_employee_code; +ALTER TABLE eg_hrms_employee ADD CONSTRAINT uk_eghrms_employee_code UNIQUE (code, tenantid); \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20190219163221__alter_remove_phone_name_clm_dml.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190219163221__alter_remove_phone_name_clm_dml.sql new file mode 100644 index 00000000000..851d369e121 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190219163221__alter_remove_phone_name_clm_dml.sql @@ -0,0 +1,2 @@ +ALTER TABLE eg_hrms_employee DROP COLUMN phone; +ALTER TABLE eg_hrms_employee DROP COLUMN name; \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20190301154105__alter_add_isactive_ddl.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190301154105__alter_add_isactive_ddl.sql new file mode 100644 index 00000000000..9ddb8794f36 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190301154105__alter_add_isactive_ddl.sql @@ -0,0 +1,6 @@ +ALTER TABLE eg_hrms_departmentaltests ADD COLUMN isActive BOOLEAN; +ALTER TABLE eg_hrms_educationaldetails ADD COLUMN isActive BOOLEAN; +ALTER TABLE eg_hrms_jurisdiction ADD COLUMN isActive BOOLEAN; +ALTER TABLE eg_hrms_assignment ADD COLUMN isActive BOOLEAN; +ALTER TABLE eg_hrms_deactivationdetails ADD COLUMN isActive BOOLEAN; +ALTER TABLE eg_hrms_servicehistory ADD COLUMN isActive BOOLEAN; \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20201005230836__eg_hrms_employee_index_ddl.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20201005230836__eg_hrms_employee_index_ddl.sql new file mode 100644 index 00000000000..b9b8017f1eb --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20201005230836__eg_hrms_employee_index_ddl.sql @@ -0,0 +1 @@ + CREATE index if not exists idx_eg_hrms_employee_tenantid ON eg_hrms_employee USING btree (tenantid); diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20201223230836__eg_hrms_employee_reactivation_details_index_ddl.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20201223230836__eg_hrms_employee_reactivation_details_index_ddl.sql new file mode 100644 index 00000000000..2c4b6633804 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20201223230836__eg_hrms_employee_reactivation_details_index_ddl.sql @@ -0,0 +1,19 @@ + ALTER TABLE eg_hrms_employee ADD COLUMN reactivateemployee BOOLEAN; + + CREATE TABLE eg_hrms_reactivationdetails ( + uuid CHARACTER VARYING(1024) NOT NULL, + employeeid CHARACTER VARYING(1024) NOT NULL, + reasonforreactivation CHARACTER VARYING(250), + effectivefrom BIGINT, + ordernumber CHARACTER VARYING(250), + remarks CHARACTER VARYING(250), + tenantid CHARACTER VARYING(250) NOT NULL, + createdby CHARACTER VARYING(250) NOT NULL, + createddate BIGINT NOT NULL, + lastmodifiedby CHARACTER VARYING(250), + lastModifiedDate BIGINT, + + CONSTRAINT pk_eghrms_reactivationdetails PRIMARY KEY (uuid), + CONSTRAINT fk_eghrms_reactivationdetails_employeeid FOREIGN KEY (employeeid) REFERENCES eg_hrms_employee (uuid) ON DELETE CASCADE + + ); diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20201228172710__reactivation_indexes_ddl.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20201228172710__reactivation_indexes_ddl.sql new file mode 100644 index 00000000000..96f05aae2ee --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20201228172710__reactivation_indexes_ddl.sql @@ -0,0 +1 @@ +CREATE INDEX reactivation_employeeid_idx ON eg_hrms_reactivationdetails ("employeeid"); \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/resources/db/migration/seed/.gitkeep b/core-services/egov-hrms/src/main/resources/db/migration/seed/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/core-services/egov-hrms/src/test/resources/application.properties b/core-services/egov-hrms/src/test/resources/application.properties new file mode 100644 index 00000000000..f8216b1d92e --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/application.properties @@ -0,0 +1,108 @@ +#---------------------------- DATABASE CONFIGURATIONS -----------------------------# +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/hr_employee_db +spring.datasource.username=postgres +spring.datasource.password=postgres + +#----------------------------- FLYWAY CONFIGURATIONS ------------------------------# +flyway.url=jdbc:postgresql://localhost:5432/hr_employee_db +flyway.user=postgres +flyway.password=postgres +flyway.table=hr_employee_schema_version +flyway.baseline-on-migrate=true +flyway.outOfOrder=true +flyway.locations=db/migration/main,db/migration/seed + +#--------------------------- PATH & PORT CONFIGURATIONS ---------------------------# +server.contextPath=/hr-employee-v2 +server.port=9999 + +#---------------------------- TIMEZONE CONFIGURATIONS -----------------------------# +app.timezone=UTC + +#-------------------------- EXTERNAL API CONFIGURATIONS ---------------------------# +egov.services.data_sync_employee.required = false + +# HR-EMPLOYEE (SELF) SERVICE PATH +egov.services.hr_employee_service.hostname=https://dev.digit.org +egov.services.hr_employee_service.basepath=/hr-employee-v2 +egov.services.hr_employee_service.employee.createpath=/employees/_create +egov.services.hr_employee_service.default.password=abcdefgh + +# USER SERVICE PATH +egov.services.users_service.hostname=https://dev.digit.org +egov.services.users_service.users.basepath=/user +egov.services.users_service.users.searchpath=/v1/_search +egov.services.users_service.users.createpath=/users/_createnovalidate +egov.services.users_service.users.updatepath=/users/_updatenovalidate + +# HR-MASTERS SERVICE PATH +egov.services.hr_masters_service.hostname=https://dev.digit.org +egov.services.hr_masters_service.basepath=/hr-masters-v2 +egov.services.hr_masters_service.positions.searchpath=/positions/_search +egov.services.hr_masters_service.designations.searchpath=/designations/_search +egov.services.hr_masters_service.hr_configurations.searchpath=/hrconfigurations/_search +egov.services.hr_masters_service.vacantpositions.searchpath=/vacantpositions/_search +egov.services.hr_masters_service.empstatus.searchpath=//hrstatuses/_search +egov.services.hr_masters_service.emptype.searchpath=/employeetypes/_search + +# HYBRID-DATA-SYNC SERVICE PATH +egov.services.data_sync_employee_service.hostname=http://dev.digit.org +egov.services.data_sync_employee_service.basepath=/data-sync-employee +egov.services.data_sync_employee_service.createpath=/datasync/_create + +# ID GENERATION SERVICE PATH +egov.services.egov_idgen.hostname=http://dev.digit.org +egov.services.egov_idgen.createpath=/egov-idgen/id/_generate +egov.services.egov_idgen.emp.code.name=employee.code +egov.services.egov_idgen.emp.code.format=EMP_[SEQ_EMPLOYEE_CODE] + +# COMMON-WORKFLOW SERVICE PATH +egov.services.common_workflows_service.hostname=http://dev.digit.org +egov.services.common_workflows_service.searchpath=/egov-common-workflows/tasks/_search + +# MDMS SERVICE PATH +egov.services.egov_mdms.hostname=https://dev.digit.org/ +egov.services.egov_mdms.searchpath=egov-mdms-service/v1/_search + +# ERP SERVICE PATH +egov.services.eis_service.hostname=http://dev.digit.org +egov.municipality.host=http://kurnool-pilot-services.egovernments.org/ +egov.services.eis_service.employeeposition.searchpath=employeepositions/_search + +#------------------------------ KAFKA CONFIGURATIONS ------------------------------# +# KAFKA SERVER CONFIGURATIONS +spring.kafka.bootstrap.servers=localhost:9092 + +# SPRING KAFKA CONSUMER CONFIGURATIONS +spring.kafka.consumer.value-deserializer=org.egov.tracer.kafka.deserializer.HashMapDeserializer +spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer +spring.kafka.consumer.group-id=employee-group1 + +# SPRING KAFKA PRODUCER CONFIGURATIONS +spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer +spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer + +# KAFKA TOPIC CONFIGURATIONS +kafka.topics.notification.sms.name=egov.employee +kafka.topics.notification.sms.id=employee +kafka.topics.notification.sms.group=employee-group1 +kafka.topics.employee.savedb.name=egov.employee +kafka.topics.employee.savedb.key=employee-save +kafka.topics.employee.finance.name=egov.employee.finance +kafka.topics.employee.finance.key=employee-finance +kafka.topics.employee.updatedb.name=egov.employee.update +kafka.topics.nominee.savedb.name=hr-employee.nominee.save +kafka.topics.nominee.savedb.key=hr-employee.nominee.save.key +kafka.topics.nominee.updatedb.name=hr-employee.nominee.update +kafka.topics.nominee.updatedb.key=hr-employee.nominee.update.key +kafka.topics.assignment.update.name=hr-employee.assignment.update +kafka.topics.assignment.update.key=hr-employee.assignment.update.key + +#------------------------------ TRACER CONFIGURATIONS -----------------------------# +# tracer.detailed.tracing.enabled=false + +#------------------------------ LOGGER CONFIGURATIONS -----------------------------# +logging.pattern.console=%clr(%X{CORRELATION_ID:-}) %clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx} + +log4j.logger.org.springframework.jdbc.core = TRACE \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/config/application-config.properties b/core-services/egov-hrms/src/test/resources/config/application-config.properties new file mode 100644 index 00000000000..8ade6ea4997 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/config/application-config.properties @@ -0,0 +1,17 @@ +#----------------------- DEFAULT PAGINATION CONFIGURATIONS ------------------------# +egov.services.emp.search.pagesize.default=200 +egov.services.emp.search.pageno.max=50 +egov.services.emp.search.pagesize.max=500 + + +#------------------------- CODE & SEQUENCE CONFIGURATIONS -------------------------# + +# Already configured in ApplicationConfiguration file but right now not being used. Instead using enum. +egov.services.emp.seq.assignment=seq_egeis_assignment +egov.services.emp.seq.departmentaltest=seq_egeis_departmentaltest +egov.services.emp.seq.educationalqualification=seq_egeis_educationalqualification +egov.services.emp.seq.hoddepartment=seq_egeis_hoddepartment +egov.services.emp.seq.probation=seq_egeis_probation +egov.services.emp.seq.regularisation=seq_egeis_regularisation +egov.services.emp.seq.servicehistory=seq_egeis_servicehistory +egov.services.emp.seq.technicalqualification=seq_egeis_technicalqualification diff --git a/core-services/egov-hrms/src/test/resources/db/Dockerfile b/core-services/egov-hrms/src/test/resources/db/Dockerfile new file mode 100644 index 00000000000..e7da01d7f0b --- /dev/null +++ b/core-services/egov-hrms/src/test/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"] \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migrate.sh b/core-services/egov-hrms/src/test/resources/db/migrate.sh new file mode 100644 index 00000000000..f9d6617822c --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migrate.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS -baselineOnMigrate=true -outOfOrder=true migrate diff --git a/core-services/egov-hrms/src/test/resources/db/migration/dev/V20170428152327__egeis_hremployee_sample_data_for_pgr.sql b/core-services/egov-hrms/src/test/resources/db/migration/dev/V20170428152327__egeis_hremployee_sample_data_for_pgr.sql new file mode 100644 index 00000000000..ea1477e6cb5 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/dev/V20170428152327__egeis_hremployee_sample_data_for_pgr.sql @@ -0,0 +1,18 @@ +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'narasappa' and tenantid = 'default'), '658039', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'default'); +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'ramana' and tenantid = 'default'), '658040', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'default'); + +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658039' and tenantid = 'default'), +(select id from egeis_position where name = 'ENG_Assistant Engineer_1' and tenantid = 'default'), NULL, NULL, NULL, +(select id from eg_department where code = 'ADM' and tenantid = 'default'), +(select id from egeis_designation where code = 'SASST' and tenantid = 'default'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'default'); +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658040' and tenantid = 'default'), +(select id from egeis_position where name = 'Acc_Senior Account_1' and tenantid = 'default'), NULL, NULL, NULL, +(select id from eg_department where code = 'ACC' and tenantid = 'default'), +(select id from egeis_designation where code = 'AO' and tenantid = 'default'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'default'); + diff --git a/core-services/egov-hrms/src/test/resources/db/migration/dev/V20170530010026__hr_employee_sample_data_for_panavel.sql b/core-services/egov-hrms/src/test/resources/db/migration/dev/V20170530010026__hr_employee_sample_data_for_panavel.sql new file mode 100644 index 00000000000..0cc581ae74c --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/dev/V20170530010026__hr_employee_sample_data_for_panavel.sql @@ -0,0 +1,20 @@ +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'admin' and tenantid = 'panavel'), '658039', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'panavel'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'panavel'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'panavel'); + +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'ajay' and tenantid = 'panavel'), '658040', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'panavel'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'panavel'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'panavel'); + +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658039' and tenantid = 'panavel'), +(select id from egeis_position where name = 'ENG_Assistant Engineer_2' and tenantid = 'panavel'), NULL, NULL, NULL, +(select id from eg_department where code = 'ADM' and tenantid = 'panavel'), +(select id from egeis_designation where code = 'SASST' and tenantid = 'panavel'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'panavel'); +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658040' and tenantid = 'panavel'), +(select id from egeis_position where name = 'Acc_Senior Account_2' and tenantid = 'panavel'), NULL, NULL, NULL, +(select id from eg_department where code = 'ENG' and tenantid = 'panavel'), +(select id from egeis_designation where code = 'AO' and tenantid = 'panavel'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'panavel'); + + diff --git a/core-services/egov-hrms/src/test/resources/db/migration/dev/V20170614093822__hr_employee_sample_data_for_default.sql b/core-services/egov-hrms/src/test/resources/db/migration/dev/V20170614093822__hr_employee_sample_data_for_default.sql new file mode 100644 index 00000000000..833a0c4c030 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/dev/V20170614093822__hr_employee_sample_data_for_default.sql @@ -0,0 +1,9 @@ +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'ravi' and tenantid = 'default'), '658041', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'default'); + +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658041' and tenantid = 'default'), +(select id from egeis_position where name = 'ENG_Junior Assistant_1' and tenantid = 'default'), NULL, NULL, NULL, +(select id from eg_department where code = 'ENG' and tenantid = 'default'), +(select id from egeis_designation where code = 'JASST' and tenantid = 'default'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'default'); \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185601__hr_employee_employee.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185601__hr_employee_employee.sql new file mode 100644 index 00000000000..3d240ac08c8 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185601__hr_employee_employee.sql @@ -0,0 +1,45 @@ +CREATE TABLE egeis_employee ( + id BIGINT NOT NULL, + code CHARACTER VARYING(250), + dateOfAppointment DATE, + dateOfJoining DATE, + dateOfRetirement DATE, + employeeStatus CHARACTER VARYING(250), + recruitmentModeId BIGINT, + recruitmentTypeId BIGINT, + recruitmentQuotaId BIGINT, + retirementAge INTEGER, + dateOfResignation DATE, + dateOfTermination DATE, + employeeTypeId BIGINT, + motherTongueId BIGINT, + religionId BIGINT, + communityId BIGINT, + categoryId BIGINT, + physicallyDisabled BOOLEAN NOT NULL, + medicalReportProduced BOOLEAN NOT NULL, + maritalStatus CHARACTER VARYING(250), + passportNo CHARACTER VARYING(250) NOT NULL, + gpfNo CHARACTER VARYING(250) NOT NULL, + bankId BIGINT, + bankBranchId BIGINT, + bankAccount CHARACTER VARYING(20) NOT NULL, + groupId BIGINT, + placeOfBirth CHARACTER VARYING(200) NOT NULL, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_employee PRIMARY KEY (Id), + CONSTRAINT uk_egeis_employee_code UNIQUE (code), + CONSTRAINT ck_egeis_employee_retirementAge CHECK (retirementAge <= 100), + CONSTRAINT ck_egeis_employee_dateOfAppointment CHECK (dateOfAppointment <= dateOfJoining), + CONSTRAINT ck_egeis_employee_dateOfRetirement CHECK (dateOfRetirement >= dateOfJoining), + CONSTRAINT ck_egeis_employee_dateOfResignation CHECK (dateOfResignation >= dateOfJoining), + CONSTRAINT ck_egeis_employee_dateOfTermination CHECK (dateOfTermination >= dateOfJoining) +); + +CREATE SEQUENCE seq_egeis_employee + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185602__hr_employee_assignment.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185602__hr_employee_assignment.sql new file mode 100644 index 00000000000..8874bba64e9 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185602__hr_employee_assignment.sql @@ -0,0 +1,31 @@ +CREATE TABLE egeis_assignment ( + id BIGINT NOT NULL, + employeeId BIGINT, + positionId BIGINT NOT NULL, + fundId BIGINT, + functionaryId BIGINT, + functionId BIGINT, + departmentId BIGINT NOT NULL, + designationId BIGINT NOT NULL, + isPrimary BOOLEAN NOT NULL, + fromDate DATE NOT NULL, + toDate DATE NOT NULL, + gradeId BIGINT, + govtOrderNumber CHARACTER VARYING(250), + createdBy BIGINT NOT NULL, + createdDate DATE NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate DATE, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_assignment PRIMARY KEY (id), + CONSTRAINT fk_egeis_assignment_employeeId FOREIGN KEY (employeeId) + REFERENCES egeis_employee (id) +); + +CREATE SEQUENCE seq_egeis_assignment + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185603__hr_employee_educationalqualification.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185603__hr_employee_educationalqualification.sql new file mode 100644 index 00000000000..2628586d321 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185603__hr_employee_educationalqualification.sql @@ -0,0 +1,24 @@ +CREATE TABLE egeis_educationalQualification ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + qualification CHARACTER VARYING(250) NOT NULL, + majorSubject CHARACTER VARYING(250), + yearOfPassing INTEGER NOT NULL, + university CHARACTER VARYING(250), + createdBy BIGINT NOT NULL, + createdDate DATE NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate DATE, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_educationalQualification PRIMARY KEY (Id), + CONSTRAINT fk_egeis_educationalQualification_employeeId FOREIGN KEY (employeeId) + REFERENCES egeis_employee (id) +); + +CREATE SEQUENCE seq_egeis_educationalQualification + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185604__hr_employee_departmentaltest.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185604__hr_employee_departmentaltest.sql new file mode 100644 index 00000000000..60fbc452966 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185604__hr_employee_departmentaltest.sql @@ -0,0 +1,23 @@ +CREATE TABLE egeis_departmentalTest ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + test CHARACTER VARYING(250) NOT NULL, + yearOfPassing INTEGER NOT NULL, + remarks CHARACTER VARYING(250), + createdBy BIGINT NOT NULL, + createdDate DATE NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate DATE, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_departmentalTest PRIMARY KEY (Id), + CONSTRAINT fk_egeis_departmentalTest_employeeId FOREIGN KEY (employeeId) + REFERENCES egeis_employee (id) +); + +CREATE SEQUENCE seq_egeis_departmentalTest + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185605__hr_employee_employee_jurisdictions.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185605__hr_employee_employee_jurisdictions.sql new file mode 100644 index 00000000000..ef7e25e8fb8 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185605__hr_employee_employee_jurisdictions.sql @@ -0,0 +1,15 @@ +CREATE TABLE egeis_employeeJurisdictions ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + jurisdictionId BIGINT NOT NULL, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_employeeJurisdictions PRIMARY KEY (Id) +); + +CREATE SEQUENCE seq_egeis_employeeJurisdictions + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185606__hr_employee_hoddepartment.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185606__hr_employee_hoddepartment.sql new file mode 100644 index 00000000000..6eb5bf38ca0 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185606__hr_employee_hoddepartment.sql @@ -0,0 +1,17 @@ +CREATE TABLE egeis_hodDepartment ( + id BIGINT NOT NULL, + departmentId BIGINT NOT NULL, + assignmentId BIGINT NOT NULL, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_hodDepartment PRIMARY KEY (Id), + CONSTRAINT egeis_hodDepartment_assignmentId FOREIGN KEY (assignmentId) + REFERENCES egeis_assignment(id) +); + +CREATE SEQUENCE seq_egeis_hodDepartment + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185607__hr_employee_employee_languages.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185607__hr_employee_employee_languages.sql new file mode 100644 index 00000000000..370f6b49244 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185607__hr_employee_employee_languages.sql @@ -0,0 +1,15 @@ +CREATE TABLE egeis_employeeLanguages ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + languageId BIGINT NOT NULL, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_employee_languages PRIMARY KEY (Id) +); + +CREATE SEQUENCE seq_egeis_employeeLanguages + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185608__hr_employee_probation.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185608__hr_employee_probation.sql new file mode 100644 index 00000000000..9b5ac43cbb5 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185608__hr_employee_probation.sql @@ -0,0 +1,25 @@ +CREATE TABLE egeis_probation ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + designationId BIGINT NOT NULL, + declaredOn DATE NOT NULL, + orderNo CHARACTER VARYING(250), + orderDate DATE, + remarks CHARACTER VARYING(250), + createdBy BIGINT NOT NULL, + createdDate DATE NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate DATE, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_probation PRIMARY KEY (Id), + CONSTRAINT fk_egeis_probation_employeeId FOREIGN KEY (employeeId) + REFERENCES egeis_employee (id) +); + +CREATE SEQUENCE seq_egeis_probation + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185609__hr_employee_regularisation.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185609__hr_employee_regularisation.sql new file mode 100644 index 00000000000..04b15a7cdb8 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185609__hr_employee_regularisation.sql @@ -0,0 +1,25 @@ +CREATE TABLE egeis_regularisation ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + designationId BIGINT NOT NULL, + declaredOn DATE NOT NULL, + orderNo CHARACTER VARYING(250), + orderDate DATE NOT NULL, + remarks CHARACTER VARYING(250), + createdBy BIGINT NOT NULL, + createdDate DATE NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate DATE, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_regularisation PRIMARY KEY (Id), + CONSTRAINT fk_egeis_regularisation_employeeId FOREIGN KEY (employeeId) + REFERENCES egeis_employee (id) +); + +CREATE SEQUENCE seq_egeis_regularisation + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185610__hr_employee_servicehistory.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185610__hr_employee_servicehistory.sql new file mode 100644 index 00000000000..ed40fb8ba5a --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185610__hr_employee_servicehistory.sql @@ -0,0 +1,24 @@ +CREATE TABLE egeis_serviceHistory ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + serviceInfo CHARACTER VARYING(250) NOT NULL, + serviceFrom DATE NOT NULL, + remarks CHARACTER VARYING(250), + orderNo CHARACTER VARYING(250), + createdBy BIGINT NOT NULL, + createdDate DATE NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate DATE, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_serviceHistory PRIMARY KEY (Id), + CONSTRAINT fk_egeis_serviceHistory_employeeId FOREIGN KEY (employeeId) + REFERENCES egeis_employee (id) +); + +CREATE SEQUENCE seq_egeis_serviceHistory + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185611__hr_employee_technicalqualification.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185611__hr_employee_technicalqualification.sql new file mode 100644 index 00000000000..85a261a8551 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185611__hr_employee_technicalqualification.sql @@ -0,0 +1,24 @@ +CREATE TABLE egeis_technicalQualification ( + id BIGINT NOT NULL, + employeeID BIGINT NOT NULL, + skill CHARACTER VARYING(250) NOT NULL, + grade CHARACTER VARYING(250), + yearOfPassing INTEGER, + remarks CHARACTER VARYING(250), + createdBy BIGINT NOT NULL, + createdDate DATE NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate DATE, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_technicalQualification PRIMARY KEY (Id), + CONSTRAINT fk_egeis_technicalQualification_employeeId FOREIGN KEY (employeeId) + REFERENCES egeis_employee (id) +); + +CREATE SEQUENCE seq_egeis_technicalQualification + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185612__hr_employee_added_and_updated_foreign_key_constraints.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185612__hr_employee_added_and_updated_foreign_key_constraints.sql new file mode 100644 index 00000000000..d2674ce5141 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185612__hr_employee_added_and_updated_foreign_key_constraints.sql @@ -0,0 +1,8 @@ +ALTER TABLE egeis_employeeJurisdictions ADD CONSTRAINT fk_egeis_employeeJurisdictions_employeeId + FOREIGN KEY (employeeId) REFERENCES egeis_employee (id); + +ALTER TABLE egeis_employeeLanguages ADD CONSTRAINT fk_egeis_employeeLanguages_employeeId + FOREIGN KEY (employeeId) REFERENCES egeis_employee (id); + +ALTER TABLE egeis_hodDepartment RENAME CONSTRAINT egeis_hodDepartment_assignmentId + TO fk_egeis_hodDepartment_assignmentId; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185613__updated_null_checks_in_egeis_employee_table.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185613__updated_null_checks_in_egeis_employee_table.sql new file mode 100644 index 00000000000..4cc00f0605d --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185613__updated_null_checks_in_egeis_employee_table.sql @@ -0,0 +1,9 @@ +ALTER TABLE egeis_employee ALTER COLUMN code SET NOT NULL; +ALTER TABLE egeis_employee ALTER COLUMN employeeStatus SET NOT NULL; +ALTER TABLE egeis_employee ALTER COLUMN employeeTypeId SET NOT NULL; +ALTER TABLE egeis_employee ALTER COLUMN physicallyDisabled DROP NOT NULL; +ALTER TABLE egeis_employee ALTER COLUMN medicalReportProduced DROP NOT NULL; +ALTER TABLE egeis_employee ALTER COLUMN passportNo DROP NOT NULL; +ALTER TABLE egeis_employee ALTER COLUMN gpfNo DROP NOT NULL; +ALTER TABLE egeis_employee ALTER COLUMN bankAccount DROP NOT NULL; +ALTER TABLE egeis_employee ALTER COLUMN placeOfBirth DROP NOT NULL; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185614__updated_null_checks_in_egeis_regularisation_table.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185614__updated_null_checks_in_egeis_regularisation_table.sql new file mode 100644 index 00000000000..8c5e1be4db1 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185614__updated_null_checks_in_egeis_regularisation_table.sql @@ -0,0 +1 @@ +ALTER TABLE egeis_regularisation ALTER COLUMN orderDate DROP NOT NULL; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185615__hr_employee_employeedocuments.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185615__hr_employee_employeedocuments.sql new file mode 100644 index 00000000000..b0f7559dd17 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185615__hr_employee_employeedocuments.sql @@ -0,0 +1,18 @@ +CREATE TABLE egeis_employeeDocuments ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + document CHARACTER VARYING(1000) NOT NULL, + referenceType CHARACTER VARYING(25), + referenceId BIGINT, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_employeeDocuments PRIMARY KEY (Id), + CONSTRAINT uk_egeis_employeeDocuments_document UNIQUE (document) +); + +CREATE SEQUENCE seq_egeis_employeeDocuments + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185616__updated_unique_constraint_in_hr_employee.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185616__updated_unique_constraint_in_hr_employee.sql new file mode 100644 index 00000000000..99aa51c4de5 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185616__updated_unique_constraint_in_hr_employee.sql @@ -0,0 +1,7 @@ +TRUNCATE TABLE egeis_employee CASCADE; +TRUNCATE TABLE egeis_assignment CASCADE; + +-- EMPLOYEE TABLE CONSTRAINTS +ALTER TABLE egeis_employee ADD CONSTRAINT uk_egeis_employee_passportNo UNIQUE (passportNo); +ALTER TABLE egeis_employee ADD CONSTRAINT uk_egeis_employee_gpfNo UNIQUE (gpfNo); +ALTER TABLE egeis_employee ADD CONSTRAINT uk_egeis_employee_bankAccount UNIQUE (bankAccount); diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185617__updated_createdDate_and_lastModifiedDate_columns.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185617__updated_createdDate_and_lastModifiedDate_columns.sql new file mode 100644 index 00000000000..d16112e9c51 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185617__updated_createdDate_and_lastModifiedDate_columns.sql @@ -0,0 +1,20 @@ +ALTER TABLE egeis_assignment ALTER COLUMN createdDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (createdDate::TIMESTAMP WITHOUT TIME ZONE); +ALTER TABLE egeis_assignment ALTER COLUMN lastModifiedDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (lastModifiedDate::TIMESTAMP WITHOUT TIME ZONE); + +ALTER TABLE egeis_departmentaltest ALTER COLUMN createdDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (createdDate::TIMESTAMP WITHOUT TIME ZONE); +ALTER TABLE egeis_departmentaltest ALTER COLUMN lastModifiedDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (lastModifiedDate::TIMESTAMP WITHOUT TIME ZONE); + +ALTER TABLE egeis_educationalqualification ALTER COLUMN createdDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (createdDate::TIMESTAMP WITHOUT TIME ZONE); +ALTER TABLE egeis_educationalqualification ALTER COLUMN lastModifiedDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (lastModifiedDate::TIMESTAMP WITHOUT TIME ZONE); + +ALTER TABLE egeis_probation ALTER COLUMN createdDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (createdDate::TIMESTAMP WITHOUT TIME ZONE); +ALTER TABLE egeis_probation ALTER COLUMN lastModifiedDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (lastModifiedDate::TIMESTAMP WITHOUT TIME ZONE); + +ALTER TABLE egeis_regularisation ALTER COLUMN createdDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (createdDate::TIMESTAMP WITHOUT TIME ZONE); +ALTER TABLE egeis_regularisation ALTER COLUMN lastModifiedDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (lastModifiedDate::TIMESTAMP WITHOUT TIME ZONE); + +ALTER TABLE egeis_servicehistory ALTER COLUMN createdDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (createdDate::TIMESTAMP WITHOUT TIME ZONE); +ALTER TABLE egeis_servicehistory ALTER COLUMN lastModifiedDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (lastModifiedDate::TIMESTAMP WITHOUT TIME ZONE); + +ALTER TABLE egeis_technicalqualification ALTER COLUMN createdDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (createdDate::TIMESTAMP WITHOUT TIME ZONE); +ALTER TABLE egeis_technicalqualification ALTER COLUMN lastModifiedDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (lastModifiedDate::TIMESTAMP WITHOUT TIME ZONE); diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185618__updated_combination_pk.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185618__updated_combination_pk.sql new file mode 100644 index 00000000000..efdce215e6f --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185618__updated_combination_pk.sql @@ -0,0 +1,89 @@ +---------------------------- DROP FOREIGN KEYS ---------------------------- + +ALTER TABLE egeis_assignment DROP CONSTRAINT fk_egeis_assignment_employeeid; +ALTER TABLE egeis_hoddepartment DROP CONSTRAINT fk_egeis_hoddepartment_assignmentid; +ALTER TABLE egeis_employeejurisdictions DROP CONSTRAINT fk_egeis_employeejurisdictions_employeeid; +ALTER TABLE egeis_employeelanguages DROP CONSTRAINT fk_egeis_employeelanguages_employeeid; +ALTER TABLE egeis_departmentaltest DROP CONSTRAINT fk_egeis_departmentaltest_employeeid; +ALTER TABLE egeis_educationalqualification DROP CONSTRAINT fk_egeis_educationalqualification_employeeid; +ALTER TABLE egeis_probation DROP CONSTRAINT fk_egeis_probation_employeeid; +ALTER TABLE egeis_regularisation DROP CONSTRAINT fk_egeis_regularisation_employeeid; +ALTER TABLE egeis_servicehistory DROP CONSTRAINT fk_egeis_servicehistory_employeeid; +ALTER TABLE egeis_technicalqualification DROP CONSTRAINT fk_egeis_technicalqualification_employeeid; + + +--------------------------- UPDATE PRIMARY KEYS --------------------------- + +-- EGEIS_EMPLOYEE TABLE +ALTER TABLE egeis_employee DROP CONSTRAINT uk_egeis_employee_bankaccount; +ALTER TABLE egeis_employee DROP CONSTRAINT pk_egeis_employee; +ALTER TABLE egeis_employee ADD CONSTRAINT pk_egeis_employee PRIMARY KEY (id, tenantId); + +-- EGEIS_ASSIGNMENT TABLE +ALTER TABLE egeis_assignment DROP CONSTRAINT pk_egeis_assignment; +ALTER TABLE egeis_assignment ADD CONSTRAINT pk_egeis_assignment PRIMARY KEY (id, tenantId); + +-- EGEIS_HODDEPARTMENT TABLE +ALTER TABLE egeis_hoddepartment DROP CONSTRAINT pk_egeis_hoddepartment; +ALTER TABLE egeis_hoddepartment ADD CONSTRAINT pk_egeis_hoddepartment PRIMARY KEY (id, tenantId); + +-- EGEIS_EMPLOYEEDOCUMENTS TABLE +ALTER TABLE egeis_employeedocuments DROP CONSTRAINT pk_egeis_employeedocuments; +ALTER TABLE egeis_employeedocuments ADD CONSTRAINT pk_egeis_employeedocuments PRIMARY KEY (id, tenantId); + +-- EGEIS_EMPLOYEEJURISDICTIONS TABLE +ALTER TABLE egeis_employeejurisdictions DROP CONSTRAINT pk_egeis_employeejurisdictions; +ALTER TABLE egeis_employeejurisdictions ADD CONSTRAINT pk_egeis_employeejurisdictions PRIMARY KEY (id, tenantId); + +-- EGEIS_EMPLOYEELANGUAGES TABLE +ALTER TABLE egeis_employeelanguages DROP CONSTRAINT pk_egeis_employee_languages; +ALTER TABLE egeis_employeelanguages ADD CONSTRAINT pk_egeis_employeelanguages PRIMARY KEY (id, tenantId); + +-- EGEIS_DEPARTMENTALTEST TABLE +ALTER TABLE egeis_departmentaltest DROP CONSTRAINT pk_egeis_departmentaltest; +ALTER TABLE egeis_departmentaltest ADD CONSTRAINT pk_egeis_departmentaltest PRIMARY KEY (id, tenantId); + +-- EGEIS_EDUCATIONALQUALIFICATION TABLE +ALTER TABLE egeis_educationalqualification DROP CONSTRAINT pk_egeis_educationalqualification; +ALTER TABLE egeis_educationalqualification ADD CONSTRAINT pk_egeis_educationalqualification PRIMARY KEY (id, tenantId); + +-- EGEIS_PROBATION TABLE +ALTER TABLE egeis_probation DROP CONSTRAINT pk_egeis_probation; +ALTER TABLE egeis_probation ADD CONSTRAINT pk_egeis_probation PRIMARY KEY (id, tenantId); + +-- EGEIS_REGULARISATION TABLE +ALTER TABLE egeis_regularisation DROP CONSTRAINT pk_egeis_regularisation; +ALTER TABLE egeis_regularisation ADD CONSTRAINT pk_egeis_regularisation PRIMARY KEY (id, tenantId); + +-- EGEIS_SERVICEHISTORY TABLE +ALTER TABLE egeis_servicehistory DROP CONSTRAINT pk_egeis_servicehistory; +ALTER TABLE egeis_servicehistory ADD CONSTRAINT pk_egeis_servicehistory PRIMARY KEY (id, tenantId); + +-- EGEIS_TECHNICALQUALIFICATION TABLE +ALTER TABLE egeis_technicalqualification DROP CONSTRAINT pk_egeis_technicalqualification; +ALTER TABLE egeis_technicalqualification ADD CONSTRAINT pk_egeis_technicalqualification PRIMARY KEY (id, tenantId); + + +-------------------------- RECREATE FOREIGN KEYS -------------------------- + +ALTER TABLE egeis_assignment ADD CONSTRAINT fk_egeis_assignment_employeeid FOREIGN KEY (employeeid, tenantId) + REFERENCES egeis_employee (id, tenantId); +ALTER TABLE egeis_hoddepartment ADD CONSTRAINT fk_egeis_hoddepartment_assignmentid FOREIGN KEY (assignmentid, tenantId) + REFERENCES egeis_assignment (id, tenantId); +ALTER TABLE egeis_employeejurisdictions ADD CONSTRAINT fk_egeis_employeejurisdictions_employeeid FOREIGN KEY (employeeid, tenantId) + REFERENCES egeis_employee (id, tenantId); +ALTER TABLE egeis_employeelanguages ADD CONSTRAINT fk_egeis_employeelanguages_employeeid FOREIGN KEY (employeeid, tenantId) + REFERENCES egeis_employee (id, tenantId); +ALTER TABLE egeis_departmentaltest ADD CONSTRAINT fk_egeis_departmentaltest_employeeid FOREIGN KEY (employeeid, tenantId) + REFERENCES egeis_employee (id, tenantId); +ALTER TABLE egeis_educationalqualification ADD CONSTRAINT fk_egeis_educationalqualification_employeeid FOREIGN KEY (employeeid, tenantId) + REFERENCES egeis_employee (id, tenantId); +ALTER TABLE egeis_probation ADD CONSTRAINT fk_egeis_probation_employeeid FOREIGN KEY (employeeid, tenantId) + REFERENCES egeis_employee (id, tenantId); +ALTER TABLE egeis_regularisation ADD CONSTRAINT fk_egeis_regularisation_employeeid FOREIGN KEY (employeeid, tenantId) + REFERENCES egeis_employee (id, tenantId); +ALTER TABLE egeis_servicehistory ADD CONSTRAINT fk_egeis_servicehistory_employeeid FOREIGN KEY (employeeid, tenantId) + REFERENCES egeis_employee (id, tenantId); +ALTER TABLE egeis_technicalqualification ADD CONSTRAINT fk_egeis_technicalqualification_employeeid FOREIGN KEY (employeeid, tenantId) + REFERENCES egeis_employee (id, tenantId); + diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185619__updated_foreign_key_names.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185619__updated_foreign_key_names.sql new file mode 100644 index 00000000000..8e5fe900872 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185619__updated_foreign_key_names.sql @@ -0,0 +1,29 @@ +ALTER TABLE egeis_assignment + RENAME CONSTRAINT fk_egeis_assignment_employeeid TO fk_egeis_assignment_employeeid_tenantid; + +ALTER TABLE egeis_hoddepartment + RENAME CONSTRAINT fk_egeis_hoddepartment_assignmentid TO fk_egeis_hoddepartment_assignmentid_tenantid; + +ALTER TABLE egeis_employeejurisdictions + RENAME CONSTRAINT fk_egeis_employeejurisdictions_employeeid TO fk_egeis_employeejurisdictions_employeeid_tenantid; + +ALTER TABLE egeis_employeelanguages + RENAME CONSTRAINT fk_egeis_employeelanguages_employeeid TO fk_egeis_employeelanguages_employeeid_tenantid; + +ALTER TABLE egeis_departmentaltest + RENAME CONSTRAINT fk_egeis_departmentaltest_employeeid TO fk_egeis_departmentaltest_employeeid_tenantid; + +ALTER TABLE egeis_educationalqualification + RENAME CONSTRAINT fk_egeis_educationalqualification_employeeid TO fk_egeis_educationalqualification_employeeid_tenantid; + +ALTER TABLE egeis_probation + RENAME CONSTRAINT fk_egeis_probation_employeeid TO fk_egeis_probation_employeeid_tenantid; + +ALTER TABLE egeis_regularisation + RENAME CONSTRAINT fk_egeis_regularisation_employeeid TO fk_egeis_regularisation_employeeid_tenantid; + +ALTER TABLE egeis_servicehistory + RENAME CONSTRAINT fk_egeis_servicehistory_employeeid TO fk_egeis_servicehistory_employeeid_tenantid; + +ALTER TABLE egeis_technicalqualification + RENAME CONSTRAINT fk_egeis_technicalqualification_employeeid TO fk_egeis_technicalqualification_employeeid_tenantid; diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170420145502__update_combination_uk.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170420145502__update_combination_uk.sql new file mode 100644 index 00000000000..76cfc669407 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170420145502__update_combination_uk.sql @@ -0,0 +1,12 @@ +-------------------------UPDATE UNIQUE KEY CONSTRAINT------------------------ + +--EGEIS_EMPLOYEE + +ALTER TABLE egeis_employee DROP CONSTRAINT if exists uk_egeis_employee_code; +ALTER TABLE egeis_employee ADD CONSTRAINT uk_egeis_employee_code UNIQUE (code,tenantid); + +ALTER TABLE egeis_employee DROP CONSTRAINT if exists uk_egeis_employee_passportNo; +ALTER TABLE egeis_employee ADD CONSTRAINT uk_egeis_employee_passportNo UNIQUE (passportNo,tenantid); + +ALTER TABLE egeis_employee DROP CONSTRAINT if exists uk_egeis_employee_gpfNo; +ALTER TABLE egeis_employee ADD CONSTRAINT uk_egeis_employee_gpfNo UNIQUE (gpfNo,tenantid); \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170502150908__updated_employeestatus_column_datatype.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170502150908__updated_employeestatus_column_datatype.sql new file mode 100644 index 00000000000..4c856708382 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170502150908__updated_employeestatus_column_datatype.sql @@ -0,0 +1 @@ +ALTER TABLE egeis_employee ALTER COLUMN employeeStatus TYPE BIGINT USING (employeeStatus::BIGINT); diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170509104227__hr_employee_add_lastmodifieddate.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170509104227__hr_employee_add_lastmodifieddate.sql new file mode 100644 index 00000000000..03ce59abaa8 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170509104227__hr_employee_add_lastmodifieddate.sql @@ -0,0 +1,3 @@ +alter table egeis_employee add column lastmodifieddate TIMESTAMP WITHOUT TIME ZONE default now(); + +alter table egeis_employeejurisdictions add column lastmodifieddate TIMESTAMP WITHOUT TIME ZONE default now(); \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170509121707__hr_hoddepartment_add_lastmodifieddate.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170509121707__hr_hoddepartment_add_lastmodifieddate.sql new file mode 100644 index 00000000000..318e17addaa --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170509121707__hr_hoddepartment_add_lastmodifieddate.sql @@ -0,0 +1 @@ +alter table egeis_hoddepartment add column lastmodifieddate TIMESTAMP WITHOUT TIME ZONE default now(); diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170525144339__hr_employee_added_createdBy_createdDate_lastModifiedBy_lastModifiedDate_columns.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170525144339__hr_employee_added_createdBy_createdDate_lastModifiedBy_lastModifiedDate_columns.sql new file mode 100644 index 00000000000..e06605f3f10 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170525144339__hr_employee_added_createdBy_createdDate_lastModifiedBy_lastModifiedDate_columns.sql @@ -0,0 +1,7 @@ +ALTER TABLE egeis_employee DROP COLUMN IF EXISTS createdBy; +ALTER TABLE egeis_employee DROP COLUMN IF EXISTS createdDate; +ALTER TABLE egeis_employee DROP COLUMN IF EXISTS lastModifiedBy; + +ALTER TABLE egeis_employee ADD COLUMN createdBy BIGINT NOT NULL DEFAULT 1; +ALTER TABLE egeis_employee ADD COLUMN createdDate TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT now(); +ALTER TABLE egeis_employee ADD COLUMN lastModifiedBy BIGINT; diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170609165847__egeis_nominee_table.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170609165847__egeis_nominee_table.sql new file mode 100644 index 00000000000..ff10ad6733e --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170609165847__egeis_nominee_table.sql @@ -0,0 +1,30 @@ +CREATE TABLE egeis_nominee ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + name CHARACTER VARYING(100) NOT NULL, + gender CHARACTER VARYING(15) NOT NULL, + dateOfBirth BIGINT NOT NULL, + maritalStatus CHARACTER VARYING(15) NOT NULL, + relationship CHARACTER VARYING(20) NOT NULL, + bankId BIGINT, + bankBranchId BIGINT, + bankAccount CHARACTER VARYING(20), + nominated boolean NOT NULL, + employed boolean NOT NULL, + createdBy BIGINT NOT NULL, + createdDate BIGINT NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate BIGINT, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_nominee PRIMARY KEY (id, tenantId), + CONSTRAINT fk_egeis_nominee_employeeId FOREIGN KEY (employeeId, tenantId) + REFERENCES egeis_employee (id, tenantId) +); + +CREATE SEQUENCE seq_egeis_nominee + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170703101329__dropped_unique_document_constraint_from_egeis_employeedocuments.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170703101329__dropped_unique_document_constraint_from_egeis_employeedocuments.sql new file mode 100644 index 00000000000..f8e86ac0fbe --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170703101329__dropped_unique_document_constraint_from_egeis_employeedocuments.sql @@ -0,0 +1,2 @@ +-- Dropping since now the document attachments are already going to be UUID +ALTER TABLE egeis_employeeDocuments DROP CONSTRAINT uk_egeis_employeeDocuments_document; diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170707184507__egeis_aprdetails_table.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170707184507__egeis_aprdetails_table.sql new file mode 100644 index 00000000000..fa3734d30bd --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170707184507__egeis_aprdetails_table.sql @@ -0,0 +1,24 @@ +CREATE TABLE egeis_aprDetails ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + yearOfSubmission INTEGER NOT NULL, + detailsSubmitted BOOLEAN NOT NULL, + dateOfSubmission DATE, + remarks CHARACTER VARYING(1024), + createdBy BIGINT NOT NULL, + createdDate TIMESTAMP WITHOUT TIME ZONE NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate TIMESTAMP WITHOUT TIME ZONE, + tenantId CHARACTER VARYING(256) NOT NULL, + + CONSTRAINT pk_egeis_aprDetails PRIMARY KEY (id, tenantId), + CONSTRAINT fk_egeis_aprDetails_employeeId FOREIGN KEY (employeeId, tenantId) + REFERENCES egeis_employee (id, tenantId) +); + +CREATE SEQUENCE seq_egeis_aprDetails + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20171023104634__hr_employee_add_ifsccode.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20171023104634__hr_employee_add_ifsccode.sql new file mode 100644 index 00000000000..668fcadfe25 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20171023104634__hr_employee_add_ifsccode.sql @@ -0,0 +1 @@ +alter table egeis_employee add column ifscCode CHARACTER VARYING(20); \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20180310133312__hr_employee_disciplinary.ddl.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180310133312__hr_employee_disciplinary.ddl.sql new file mode 100644 index 00000000000..5523340f27f --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180310133312__hr_employee_disciplinary.ddl.sql @@ -0,0 +1,56 @@ + CREATE TABLE egeis_disciplinary ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + gistCase CHARACTER VARYING(250) NOT NULL, + disciplinaryAuthority CHARACTER VARYING(250) NOT NULL, + orderNo CHARACTER VARYING(250) NOT NULL, + orderDate DATE NOT NULL, + memoNo CHARACTER VARYING(250) NOT NULL, + memoDate DATE NOT NULL, + memoServingDate DATE NOT NULL, + dateOfReceiptMemoDate DATE, + explanationAccepted BOOLEAN, + chargeMemoNo CHARACTER VARYING(250), + chargeMemoDate DATE, + dateOfReceiptToChargeMemoDate DATE, + accepted BOOLEAN, + dateOfAppointmentOfEnquiryOfficerDate DATE, + enquiryOfficerName CHARACTER VARYING(250), + dateOfAppointmentOfPresentingOfficer DATE , + presentingOfficerName CHARACTER VARYING(250), + findingsOfEO CHARACTER VARYING(250), + enquiryReportSubmittedDate DATE, + dateOfCommunicationOfER DATE, + dateOfSubmissionOfExplanationByCO DATE, + acceptanceOfExplanation BOOLEAN, + proposedPunishmentByDA CHARACTER VARYING(250), + showCauseNoticeNo CHARACTER VARYING(250), + showCauseNoticeDate DATE, + showCauseNoticeServingDate DATE, + explanationToShowCauseNotice CHARACTER VARYING(250), + explanationToShowCauseNoticeAccepted BOOLEAN, + punishmentAwarded CHARACTER VARYING(250) , + proceedingsNumber CHARACTER VARYING(250), + proceedingsDate DATE, + proceedingsServingDate DATE, + courtCase BOOLEAN, + courtOrderNo CHARACTER VARYING(250), + courtOrderDate DATE, + gistOfDirectionIssuedByCourt CHARACTER VARYING(250), + createdBy BIGINT NOT NULL, + createdDate DATE NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate DATE, + tenantId CHARACTER VARYING(250) NOT NULL, + CONSTRAINT pk_egeis_disciplinary PRIMARY KEY (id,tenantId), + CONSTRAINT fk_egeis_disciplinary_employeeId FOREIGN KEY (employeeId,tenantId) + REFERENCES egeis_employee (id,tenantId) +); + +CREATE SEQUENCE seq_egeis_disciplinary + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20180310133625__hr_employee_disciplinary_documents.ddl.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180310133625__hr_employee_disciplinary_documents.ddl.sql new file mode 100644 index 00000000000..a561aa45ee8 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180310133625__hr_employee_disciplinary_documents.ddl.sql @@ -0,0 +1,15 @@ +CREATE TABLE egeis_disciplinaryDocuments ( + id BIGINT NOT NULL, + disciplinaryId BIGINT NOT NULL, + documentType CHARACTER VARYING(25) , + filestoreId CHARACTER VARYING NOT NULL, + tenantId CHARACTER VARYING (250) NOT NULL, + CONSTRAINT pk_egeis_disciplinaryDocuments PRIMARY KEY (id,tenantid) +); + +CREATE SEQUENCE seq_egeis_disciplinaryDocument + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20180312150245__hr_employee_disciplinary_alter_add_column.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180312150245__hr_employee_disciplinary_alter_add_column.sql new file mode 100644 index 00000000000..ae5f0fd4adb --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180312150245__hr_employee_disciplinary_alter_add_column.sql @@ -0,0 +1,7 @@ +alter table egeis_disciplinary add column courtOrderType CHARACTER VARYING(250); + +alter table egeis_disciplinary add column presentingOfficerDesignation CHARACTER VARYING(250); + +alter table egeis_disciplinary add column enquiryOfficerDesignation CHARACTER VARYING(250); + +alter table egeis_disciplinary alter column memoServingDate drop NOT NULL; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20180314134356__hr_employee_disciplinary_alter_length_modify.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180314134356__hr_employee_disciplinary_alter_length_modify.sql new file mode 100644 index 00000000000..c22578e6118 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180314134356__hr_employee_disciplinary_alter_length_modify.sql @@ -0,0 +1,14 @@ +ALTER TABLE egeis_disciplinary + ALTER COLUMN gistcase TYPE character varying(1000); + +ALTER TABLE egeis_disciplinary + ALTER COLUMN findingsofeo TYPE character varying(1000); + +ALTER TABLE egeis_disciplinary + ALTER COLUMN proposedpunishmentbyda TYPE character varying(1000); + +ALTER TABLE egeis_disciplinary + ALTER COLUMN explanationtoshowcausenotice TYPE character varying(1000); + +ALTER TABLE egeis_disciplinary + ALTER COLUMN gistofdirectionissuedbycourt TYPE character varying(1000); \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20180315135946__hr_employee_disciplinary_alter_add_remove_columns.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180315135946__hr_employee_disciplinary_alter_add_remove_columns.sql new file mode 100644 index 00000000000..5d29e00d8d0 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180315135946__hr_employee_disciplinary_alter_add_remove_columns.sql @@ -0,0 +1,7 @@ +ALTER TABLE egeis_disciplinary DROP COLUMN orderno; + +ALTER TABLE egeis_disciplinary DROP COLUMN orderdate; + +alter table egeis_disciplinary add column punishmentimplemented BOOLEAN; + +alter table egeis_disciplinary add column enddateofpunishment DATE; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20180316163101__hr_employee_servicehistory_add_column.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180316163101__hr_employee_servicehistory_add_column.sql new file mode 100644 index 00000000000..44e85f76af0 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180316163101__hr_employee_servicehistory_add_column.sql @@ -0,0 +1,8 @@ +alter table egeis_servicehistory +add column city CHARACTER VARYING(250), +add column department CHARACTER VARYING(250), +add column designation CHARACTER VARYING(250), +add column positionId BIGINT, +add column serviceTo DATE, +add column isAssignmentBased BOOLEAN NOT NULL DEFAULT false, +add column assignmentId BIGINT ; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20180416144447__hr_employee_department_alter_type.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180416144447__hr_employee_department_alter_type.sql new file mode 100644 index 00000000000..2986f83d677 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180416144447__hr_employee_department_alter_type.sql @@ -0,0 +1,3 @@ +ALTER TABLE egeis_assignment ALTER COLUMN departmentId TYPE varchar(256); + +ALTER TABLE egeis_hodDepartment ALTER COLUMN departmentId TYPE varchar(256); \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20180418144447__hr_employee_designation_alter_type.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180418144447__hr_employee_designation_alter_type.sql new file mode 100644 index 00000000000..cf8dcea3f9b --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180418144447__hr_employee_designation_alter_type.sql @@ -0,0 +1 @@ +ALTER TABLE egeis_assignment ALTER COLUMN designationid TYPE varchar(256); diff --git a/core-services/egov-hrms/src/test/resources/db/migration/qa/V20170428152327__egeis_hremployee_sample_data_for_pgr.sql b/core-services/egov-hrms/src/test/resources/db/migration/qa/V20170428152327__egeis_hremployee_sample_data_for_pgr.sql new file mode 100644 index 00000000000..ea1477e6cb5 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/qa/V20170428152327__egeis_hremployee_sample_data_for_pgr.sql @@ -0,0 +1,18 @@ +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'narasappa' and tenantid = 'default'), '658039', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'default'); +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'ramana' and tenantid = 'default'), '658040', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'default'); + +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658039' and tenantid = 'default'), +(select id from egeis_position where name = 'ENG_Assistant Engineer_1' and tenantid = 'default'), NULL, NULL, NULL, +(select id from eg_department where code = 'ADM' and tenantid = 'default'), +(select id from egeis_designation where code = 'SASST' and tenantid = 'default'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'default'); +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658040' and tenantid = 'default'), +(select id from egeis_position where name = 'Acc_Senior Account_1' and tenantid = 'default'), NULL, NULL, NULL, +(select id from eg_department where code = 'ACC' and tenantid = 'default'), +(select id from egeis_designation where code = 'AO' and tenantid = 'default'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'default'); + diff --git a/core-services/egov-hrms/src/test/resources/db/migration/qa/V20170530010026__hr_employee_sample_data_for_panavel.sql b/core-services/egov-hrms/src/test/resources/db/migration/qa/V20170530010026__hr_employee_sample_data_for_panavel.sql new file mode 100644 index 00000000000..0cc581ae74c --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/qa/V20170530010026__hr_employee_sample_data_for_panavel.sql @@ -0,0 +1,20 @@ +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'admin' and tenantid = 'panavel'), '658039', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'panavel'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'panavel'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'panavel'); + +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'ajay' and tenantid = 'panavel'), '658040', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'panavel'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'panavel'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'panavel'); + +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658039' and tenantid = 'panavel'), +(select id from egeis_position where name = 'ENG_Assistant Engineer_2' and tenantid = 'panavel'), NULL, NULL, NULL, +(select id from eg_department where code = 'ADM' and tenantid = 'panavel'), +(select id from egeis_designation where code = 'SASST' and tenantid = 'panavel'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'panavel'); +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658040' and tenantid = 'panavel'), +(select id from egeis_position where name = 'Acc_Senior Account_2' and tenantid = 'panavel'), NULL, NULL, NULL, +(select id from eg_department where code = 'ENG' and tenantid = 'panavel'), +(select id from egeis_designation where code = 'AO' and tenantid = 'panavel'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'panavel'); + + diff --git a/core-services/egov-hrms/src/test/resources/db/migration/qa/V20170614093822__hr_employee_sample_data_for_default.sql b/core-services/egov-hrms/src/test/resources/db/migration/qa/V20170614093822__hr_employee_sample_data_for_default.sql new file mode 100644 index 00000000000..833a0c4c030 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/qa/V20170614093822__hr_employee_sample_data_for_default.sql @@ -0,0 +1,9 @@ +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'ravi' and tenantid = 'default'), '658041', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'default'); + +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658041' and tenantid = 'default'), +(select id from egeis_position where name = 'ENG_Junior Assistant_1' and tenantid = 'default'), NULL, NULL, NULL, +(select id from eg_department where code = 'ENG' and tenantid = 'default'), +(select id from egeis_designation where code = 'JASST' and tenantid = 'default'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'default'); \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/seed/.gitkeep b/core-services/egov-hrms/src/test/resources/db/migration/seed/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/core-services/egov-survey-services/src/main/resources/db/Dockerfile b/core-services/egov-survey-services/src/main/resources/db/Dockerfile index a5699ff7d99..e7da01d7f0b 100644 --- a/core-services/egov-survey-services/src/main/resources/db/Dockerfile +++ b/core-services/egov-survey-services/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"] +ENTRYPOINT ["/usr/bin/migrate.sh"] \ No newline at end of file diff --git a/core-services/egov-survey-services/src/main/resources/db/migrate.sh b/core-services/egov-survey-services/src/main/resources/db/migrate.sh index 43960b25cdb..f9d6617822c 100644 --- a/core-services/egov-survey-services/src/main/resources/db/migrate.sh +++ b/core-services/egov-survey-services/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/core-services/pgr-services/pom.xml b/core-services/pgr-services/pom.xml index a9746f2fd2a..f261a90cef5 100644 --- a/core-services/pgr-services/pom.xml +++ b/core-services/pgr-services/pom.xml @@ -107,7 +107,7 @@ org.postgresql postgresql - 42.2.2.jre7 + 42.7.1 org.egov @@ -115,10 +115,10 @@ 0.0.2-SNAPSHOT compile - org.flywaydb flyway-core + 9.22.3 com.itextpdf diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/consumer/MigrationConsumer.java b/core-services/pgr-services/src/main/java/org/egov/pgr/consumer/MigrationConsumer.java deleted file mode 100644 index 1e12fb16aa2..00000000000 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/consumer/MigrationConsumer.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.egov.pgr.consumer; - -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.extern.slf4j.Slf4j; -import org.egov.pgr.service.MigrationService; -import org.egov.pgr.web.models.pgrV1.ServiceResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.kafka.annotation.KafkaListener; -import org.springframework.kafka.support.KafkaHeaders; -import org.springframework.messaging.handler.annotation.Header; -import org.springframework.stereotype.Component; - -import java.util.HashMap; - -@Slf4j -@Component -public class MigrationConsumer { - - - @Autowired - private MigrationService migrationService; - - @Autowired - private ObjectMapper mapper; - - - @KafkaListener(topics = { "${pgr.kafka.migration.topic}"}) - public void listen(final HashMap record, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { - - try { - log.info("Received migration request " + record); - ServiceResponse serviceResponse = mapper.convertValue(record,ServiceResponse.class); - migrationService.migrate(serviceResponse); - } - catch (Exception e){ - log.error("Error occured while processing the record from topic : " + topic, e); - } - - } - -} diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/service/EnrichmentService.java b/core-services/pgr-services/src/main/java/org/egov/pgr/service/EnrichmentService.java index 7615c2ef8d3..1c4e2b16da8 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/service/EnrichmentService.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/service/EnrichmentService.java @@ -59,9 +59,9 @@ public void enrichCreateRequest(ServiceRequest serviceRequest){ userService.callUserService(serviceRequest); - AuditDetails auditDetails = utils.getAuditDetails(requestInfo.getUserInfo().getUuid(), service,true); + //AuditDetails auditDetails = utils.getAuditDetails(requestInfo.getUserInfo().getUuid(), service,true); - service.setAuditDetails(auditDetails); + //service.setAuditDetails(auditDetails); service.setId(UUID.randomUUID().toString()); service.getAddress().setId(UUID.randomUUID().toString()); service.getAddress().setTenantId(tenantId); diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/service/MigrationService.java b/core-services/pgr-services/src/main/java/org/egov/pgr/service/MigrationService.java deleted file mode 100644 index f6d62819d8d..00000000000 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/service/MigrationService.java +++ /dev/null @@ -1,457 +0,0 @@ -package org.egov.pgr.service; - - -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.egov.common.contract.request.User; -import org.egov.pgr.config.PGRConfiguration; -import org.egov.pgr.producer.Producer; -import org.egov.pgr.util.MigrationUtils; -import org.egov.pgr.web.models.AuditDetails; -import org.egov.pgr.web.models.Boundary; -import org.egov.pgr.web.models.Document; -import org.egov.pgr.web.models.GeoLocation; -import org.egov.pgr.web.models.ServiceRequest; -import org.egov.pgr.web.models.pgrV1.ActionHistory; -import org.egov.pgr.web.models.pgrV1.ActionInfo; -import org.egov.pgr.web.models.pgrV1.Address; -import org.egov.pgr.web.models.pgrV1.Service; -import org.egov.pgr.web.models.pgrV1.ServiceResponse; -import org.egov.pgr.web.models.workflow.ProcessInstance; -import org.egov.pgr.web.models.workflow.ProcessInstanceRequest; -import org.egov.pgr.web.models.workflow.State; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; -import org.springframework.util.ObjectUtils; - -import javax.annotation.PostConstruct; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -import static org.egov.pgr.util.PGRConstants.IMAGE_DOCUMENT_TYPE; -import static org.egov.pgr.util.PGRConstants.PGR_BUSINESSSERVICE; -import static org.egov.pgr.util.PGRConstants.PGR_MODULENAME; - -@Component -@Slf4j -public class MigrationService { - - - @Autowired - private MigrationUtils migrationUtils; - - @Autowired - private Producer producer; - - @Autowired - private PGRConfiguration config; - - private Map statusToUUIDMap; - - private Map serviceCodeToSLA; - - private final Map oldToNewStatus = new HashMap() { - { - - put("open", "PENDINGFORASSIGNMENT"); - put("assigned", "PENDINGATLME"); - put("closed", "CLOSEDAFTERRESOLUTION"); - put("rejected", "REJECTED"); - put("resolved", "RESOLVED"); - put("reassignrequested", "PENDINGFORREASSIGNMENT"); - - } - }; - - private final Map oldToNewAction = new HashMap() { - { - - put("open", "APPLY"); - put("ropen", "REOPEN"); - put("assign", "ASSIGN"); - put("reassign", "REASSIGN"); - put("resolve", "RESOLVE"); - put("close", "PENDINGFORREASSIGNMENT"); - put("reject", "REJECT"); - put("requestforreassign", "ASSIGN"); - - } - }; - - @PostConstruct - private void setStatusToUUIDMap(){ - this.statusToUUIDMap = migrationUtils.getStatusToUUIDMap(config.getTenantId()); - this.serviceCodeToSLA = migrationUtils.getServiceCodeToSLAMap(config.getTenantId()); - } - - - - - /** - * - * Comment actions has to be added in workflow - * Active field has to be added - * Media contains the complete url path instead of fileStoreId - * - * - * Data Assumptions: - * All records have actionHistory - * Is AuditDetails of old address different from service auditDetails - * Every citizen and employee has uuid - * - * - * - */ - - /* - * - * 1. Skipping records with empty actionHistory as no linking with service is possible in that case - * Images are added in workflow doument with documentType as PHOTO which is defined in constants file - * Citizen object is not migrated as it is stored in user service only it's reference i.e accountId is migrated - * Splitting Role in 'by' in actionInfo and storing only uuid not role in workflow (Why was it stored in that way?) - * Removed @Pattern in citizen from name, mobileNumber, address from SearchReponse in old pgr so that batch don't fail for any data - * id field set by generating new uuid as old one didn't have this field - * Assumed ActionHistory comes in descending order from old pgr search API - * - * - * 2. tenantid, servicecode, servicerequestid, createdby and createdtime were all NOT NULL constraints - * in PGR v1 eg_pgr_service table, hence no additional checks have been considered in the migrate flow. - * However, there is no such constraint of NOT NULL in case of description attribute, hence, a check has - * been placed here which will set the description as "NOT_SPECIFIED" in case description in v1 table is - * null. - * - * - * */ - public Map migrate(ServiceResponse serviceResponse) { - - - List servicesV1 = serviceResponse.getServices(); - List actionHistories = serviceResponse.getActionHistory(); - - Set ids = new HashSet<>(); - - servicesV1.forEach(service -> { - ids.add(service.getAuditDetails().getCreatedBy()); - ids.add(service.getAuditDetails().getLastModifiedBy()); - ids.add(service.getAccountId()); - }); - - actionHistories.forEach(actionHistory -> { - actionHistory.getActions().forEach(actionInfo -> { - - if (actionInfo.getAssignee() != null) - ids.add(actionInfo.getAssignee()); - - ids.add(actionInfo.getBy().split(":")[0]); - }); - }); - - Map idToUuidMap = migrationUtils.getIdtoUUIDMap(new LinkedList<>(ids)); - - /*############### FOR LOCAL TESTING ONLY ########################################### - Map idToUuidMap = new HashMap<>(); - for(String id : ids){ - if(id != null) - idToUuidMap.put(Long.parseLong(id), UUID.randomUUID().toString()); - } - //##################################################################################*/ - - Map response = transform(servicesV1, actionHistories, idToUuidMap); - - return response; - - } - - - /** - * @param servicesV1 - * @param actionHistories - * @return - */ - private Map transform(List servicesV1, List actionHistories, Map idToUuidMap) { - - - Map> idToActionMap = new HashMap<>(); - - for (ActionHistory actionHistory : actionHistories) { - List actions = actionHistory.getActions(); - - if (CollectionUtils.isEmpty(actions)) - log.error("Skiping record with empty actionHistory"); - - String id = actions.get(0).getBusinessKey(); - idToActionMap.put(id, actions); - } - - // Temporary for testing - List services = new LinkedList<>(); - List workflowResponse = new LinkedList<>(); - - for (Service serviceV1 : servicesV1) { - - List actionInfos = idToActionMap.get(serviceV1.getServiceRequestId()); - - Map actionUuidToSlaMap = getActionUUidToSLAMap(actionInfos, serviceV1.getServiceCode()); - - List workflows = new LinkedList<>(); - - org.egov.pgr.web.models.Service service = transformService(serviceV1, idToUuidMap); - - actionInfos.forEach(actionInfo -> { - ProcessInstance workflow = transformAction(actionInfo, idToUuidMap, actionUuidToSlaMap); - workflows.add(workflow); - }); - - - service.setApplicationStatus(oldToNewStatus.get(serviceV1.getStatus().toString())); - ProcessInstanceRequest processInstanceRequest = ProcessInstanceRequest.builder().processInstances(workflows).build(); - ServiceRequest serviceRequest = ServiceRequest.builder().service(service).build(); - //log.info("Pushing service request: " + serviceRequest); - /*#################### TEMPORARY FOR TESTING, REMOVE THE COMMENTS*/ - producer.push(config.getBatchCreateTopic(),serviceRequest); - producer.push(config.getBatchWorkflowSaveTopic(),processInstanceRequest); - - // Temporary for testing - services.add(service); - workflowResponse.addAll(workflows); - } - - Map response = new HashMap<>(); - - response.put("Service:", services); - response.put("Workflows:", workflowResponse); - - return response; - - - } - - - private org.egov.pgr.web.models.Service transformService(Service serviceV1, Map idToUuidMap) { - - String tenantId = serviceV1.getTenantId(); - String serviceCode = serviceV1.getServiceCode(); - String serviceRequestId = serviceV1.getServiceRequestId(); - String description = serviceV1.getDescription(); - String source = (!ObjectUtils.isEmpty(serviceV1.getSource())) ? serviceV1.getSource().toString() : null; - String rating = serviceV1.getRating(); - - String feedback = serviceV1.getFeedback(); - String addressInService = serviceV1.getAddress(); - String landmark = serviceV1.getLandmark(); - - Map additionalDetailMap = new HashMap<>(); - - if(!StringUtils.isEmpty(feedback)) - additionalDetailMap.put("feedback", feedback); - - if(!StringUtils.isEmpty(addressInService)) - additionalDetailMap.put("address", addressInService); - - if(!StringUtils.isEmpty(landmark)) - additionalDetailMap.put("landmark", landmark); - - /** - * AccountId is id, not uuid in old pgr. Mapping has to fetched - * of id to uuid i.e. accountId in new PGR is the UUID. - */ - - String accountId = null; - if(serviceV1.getAccountId() != null) - accountId = idToUuidMap.get(Long.parseLong(serviceV1.getAccountId())); - - AuditDetails auditDetails = serviceV1.getAuditDetails(); - - // Setting uuid in place of id in auditDetails - auditDetails.setCreatedBy(idToUuidMap.get(Long.parseLong(auditDetails.getCreatedBy()))); - auditDetails.setLastModifiedBy(auditDetails.getLastModifiedBy() != null ? idToUuidMap.get(Long.parseLong(auditDetails.getLastModifiedBy())):"NOT_SPECIFIED"); - - Object attributes = serviceV1.getAttributes(); - - - Double latitude = serviceV1.getLat(); - Double longitutude = serviceV1.getLongitutde(); - - /** - * Transform address and set geo location - */ - GeoLocation geoLocation = GeoLocation.builder().longitude(longitutude).latitude(latitude).build(); - //log.info("Address details: " + serviceV1.getAddressDetail()); - org.egov.pgr.web.models.Address address = null; - address = transformAddress(serviceV1.getAddressDetail()); - address.setGeoLocation(geoLocation); - address.setTenantId(tenantId); - - Boolean active = serviceV1.getActive(); - - // ACTIVE FLAG NEEDS TO BE ACCOUNTED FOR BELOW FOR POPULATING v2 POJO ---> - - org.egov.pgr.web.models.Service service = org.egov.pgr.web.models.Service.builder() - .id(UUID.randomUUID().toString()) - .tenantId(tenantId) - .accountId(accountId) - .additionalDetail(attributes) - .serviceCode(serviceCode) - .serviceRequestId(serviceRequestId) - .description(description) - .source(source) - .address(address) - .active(active) - .auditDetails(auditDetails) - .build(); - - if(!CollectionUtils.isEmpty(additionalDetailMap)) - service.setAdditionalDetail(additionalDetailMap); - - if (org.apache.commons.lang3.StringUtils.isNumeric(rating)) { - service.setRating(Integer.parseInt(rating)); - } - - - - - return service; - - } - - /** - * No auditDetails in address - * Geolocation will be enriched in service transform as that data is available there - * - * @param addressV1 - * @return - */ - private org.egov.pgr.web.models.Address transformAddress(Address addressV1) { - - String id = addressV1.getUuid(); - String locality = addressV1.getMohalla() != null ? addressV1.getMohalla() : "NOT_AVAILABLE"; - String colony = addressV1.getLocality(); - String city = addressV1.getCity(); - String landmark = addressV1.getLandmark(); - String houseNoAndStreetName = addressV1.getHouseNoAndStreetName(); - - /** - * FIXME : houseNoAndStreetName and colony mapping has to be corrected - */ - - org.egov.pgr.web.models.Address address = org.egov.pgr.web.models.Address.builder() - .id(id) - .locality(Boundary.builder().code(locality).build()) - .city(city) - .landmark(landmark) - .street(houseNoAndStreetName) - .region(colony) - .build(); - - return address; - - } - - - private ProcessInstance transformAction(ActionInfo actionInfo, Map idToUuidMap, Map actionUuidToSlaMap) { - - String uuid = actionInfo.getUuid(); - - // FIXME Should the role be stored - String createdBy = actionInfo.getBy().split(":")[0]; - - String tenantId = actionInfo.getTenantId(); - Long createdTime = actionInfo.getWhen(); - String businessId = actionInfo.getBusinessKey(); - String action = (!StringUtils.isEmpty(actionInfo.getAction())) ? oldToNewAction.get(actionInfo.getAction()) : "COMMENT"; - String status = actionInfo.getStatus(); - String assignee = actionInfo.getAssignee(); - String comments = actionInfo.getComment(); - List fileStoreIds = actionInfo.getMedia(); - String stateUUID = statusToUUIDMap.get(oldToNewStatus.get(status)); - - - State state = State.builder().uuid(stateUUID).state(oldToNewStatus.get(status)).build(); - - // LastmodifiedTime and by is same as that for created as every time new entry is created whenever any action is taken - AuditDetails auditDetails = AuditDetails.builder().createdBy(createdBy) - .createdTime(createdTime).lastModifiedBy(createdBy).lastModifiedTime(createdTime).build(); - - // Setting uuid in place of id in auditDetails - auditDetails.setCreatedBy(idToUuidMap.get(Long.parseLong(auditDetails.getCreatedBy()))); - auditDetails.setLastModifiedBy(idToUuidMap.get(Long.parseLong(auditDetails.getLastModifiedBy()))); - - ProcessInstance workflow = ProcessInstance.builder() - .id(uuid) - .tenantId(tenantId) - .action(action) - .comment(comments) - .businessId(businessId) - .moduleName(PGR_MODULENAME) - .state(state) - .businessService(PGR_BUSINESSSERVICE) - .businesssServiceSla(actionUuidToSlaMap.get(actionInfo.getUuid())) - .auditDetails(auditDetails) - .build(); - - - // Wrapping assignee uuid in User object to add it in workflow - if (!StringUtils.isEmpty(assignee)) { - User user = new User(); - user.setUuid(idToUuidMap.get(Long.parseLong(assignee))); - workflow.setAssignes(Collections.singletonList(user)); - } - - User assigner = new User(); - assigner.setUuid(idToUuidMap.get(Long.parseLong(createdBy))); - workflow.setAssigner(assigner); - - - // Setting the images uploaded in workflow document - if (!CollectionUtils.isEmpty(fileStoreIds)) { - List documents = new LinkedList<>(); - for (String fileStoreId : fileStoreIds) { - - if(!StringUtils.isEmpty(fileStoreId) && !fileStoreId.equalsIgnoreCase("null") - && fileStoreId.length()<=64){ - Document document = Document.builder() - .documentType(IMAGE_DOCUMENT_TYPE) - .fileStoreId(fileStoreId) - .id(UUID.randomUUID().toString()) - .build(); - documents.add(document); - } - } - workflow.setDocuments(documents); - } - - return workflow; - } - - private Map getActionUUidToSLAMap(List actionInfos, String serviceCode){ - - Map uuidTOSLAMap = new HashMap<>(); - - if(CollectionUtils.isEmpty(actionInfos)) - return uuidTOSLAMap; - - actionInfos.sort(Comparator.comparing(ActionInfo::getWhen)); - int totalCount = actionInfos.size(); - - uuidTOSLAMap.put(actionInfos.get(0).getUuid(), (serviceCodeToSLA.get(serviceCode)!=null)?serviceCodeToSLA.get(serviceCode):432000000l); - - for(int i = 1; i < totalCount; i++){ - - ActionInfo actionInfo = actionInfos.get(i); - ActionInfo previousActionInfo = actionInfos.get(i-1); - Long timeSpent = actionInfo.getWhen() - previousActionInfo.getWhen(); - Long slaLeft = uuidTOSLAMap.get(previousActionInfo.getUuid()) - timeSpent; - uuidTOSLAMap.put(actionInfo.getUuid(), slaLeft); - } - return uuidTOSLAMap; - } - -} diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/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/MigrationController.java b/core-services/pgr-services/src/main/java/org/egov/pgr/web/controllers/MigrationController.java deleted file mode 100644 index 17906846825..00000000000 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/web/controllers/MigrationController.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.egov.pgr.web.controllers; - -import lombok.extern.slf4j.Slf4j; -import org.egov.pgr.service.MigrationService; -import org.egov.pgr.web.models.pgrV1.ServiceResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; -import java.io.IOException; -import java.util.Map; - -@RestController -@RequestMapping("/migration") -@Slf4j -public class MigrationController { - - - @Autowired - private MigrationService migrationService; - - - @RequestMapping(value="/_transform", method = RequestMethod.POST) - public ResponseEntity requestsCreatePost(@Valid @RequestBody ServiceResponse request) throws IOException { - - Map response = migrationService.migrate(request); - - return new ResponseEntity<>(response, HttpStatus.OK); - - } -} 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/pgr-services/src/main/resources/db/Dockerfile b/core-services/pgr-services/src/main/resources/db/Dockerfile index a5699ff7d99..e7da01d7f0b 100644 --- a/core-services/pgr-services/src/main/resources/db/Dockerfile +++ b/core-services/pgr-services/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"] +ENTRYPOINT ["/usr/bin/migrate.sh"] \ No newline at end of file diff --git a/core-services/pgr-services/src/main/resources/db/migrate.sh b/core-services/pgr-services/src/main/resources/db/migrate.sh index 43960b25cdb..f9d6617822c 100644 --- a/core-services/pgr-services/src/main/resources/db/migrate.sh +++ b/core-services/pgr-services/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/core-services/pgr-services/src/test/resources/postman/pgr-services.postman_collection.json b/core-services/pgr-services/src/test/resources/postman/pgr-services.postman_collection.json new file mode 100644 index 00000000000..7b0756b9d94 --- /dev/null +++ b/core-services/pgr-services/src/test/resources/postman/pgr-services.postman_collection.json @@ -0,0 +1,309 @@ +{ + "info": { + "_postman_id": "bbf398e2-eeac-407e-891a-cf4f89c22ad9", + "name": "pgr-services", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "24751924" + }, + "item": [ + { + "name": "pgr search", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{devAuth}}\",\n \"userInfo\": {\n \"id\": 93,\n \"uuid\": \"56b5c31b-b843-426c-b8d5-64a4c80286aa\",\n \"userName\": \"sysadmin\",\n \"name\": null,\n \"mobileNumber\": \"3989999999\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"CSR\",\n \"code\": \"CSR\",\n \"tenantId\": \"default\"\n },\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"default\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"default\",\n \"permanentCity\": null\n },\n \"msgId\": \"1683099938019|en_MZ\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{dev}}/pgr-services/v2/request/_search?serviceRequestId=PGR-2023-05-03-000193&tenantId=default", + "host": [ + "{{dev}}" + ], + "path": [ + "pgr-services", + "v2", + "request", + "_search" + ], + "query": [ + { + "key": "ids", + "value": "39a07047-9759-4503-91ad-14cbeaa8df20", + "disabled": true + }, + { + "key": "mobileNumber", + "value": "8004376134", + "disabled": true + }, + { + "key": "serviceCode", + "value": "StreetLightNotWorking", + "disabled": true + }, + { + "key": "limit", + "value": "10", + "disabled": true + }, + { + "key": "applicationStatus", + "value": "RESOLVED", + "disabled": true + }, + { + "key": "serviceRequestId", + "value": "PGR-2023-05-03-000193" + }, + { + "key": "sortBy", + "value": "serviceRequestId", + "disabled": true + }, + { + "key": "sortOrder", + "value": "ASC", + "disabled": true + }, + { + "key": "locality", + "value": "SUN04", + "disabled": true + }, + { + "key": "tenantId", + "value": "default" + } + ] + } + }, + "response": [] + }, + { + "name": "pgr create", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"service\": {\n \"active\": true,\n \"tenantId\": \"default\",\n \"serviceCode\": \"SyncNotWorking\",\n \"description\": \"sync issue\",\n \"applicationStatus\": \"CREATED\",\n \"source\": \"web\",\n \"user\": {\n \"userName\": \"3989999999\",\n \"name\": \"Syadmin\",\n \"type\": \"EMPLOYEE\",\n \"mobileNumber\": \"3989999999\",\n \"roles\": [],\n \"tenantId\": \"default\",\n \"uuid\": \"56b5c31b-b843-426c-b8d5-64a4c80286aa\",\n \"active\": true,\n \"isDeleted\": false,\n \"rowVersion\": 1,\n \"auditDetails\": {\n \"createdBy\": \"56b5c31b-b843-426c-b8d5-64a4c80286aa\",\n \"createdTime\": 1683072000,\n \"lastModifiedBy\": \"56b5c31b-b843-426c-b8d5-64a4c80286aa\",\n \"lastModifiedTime\": 1683072000\n }\n },\n \"isDeleted\": false,\n \"rowVersion\": 1,\n \"address\": {\n \"landmark\": \"\",\n \"buildingName\": \"\",\n \"street\": \"\",\n \"pincode\": \"\",\n \"locality\": {\n \"code\": \"VFTw0jbRf1y\",\n \"name\": \"CAVINA1\"\n },\n \"geoLocation\": {}\n },\n \"additionalDetail\": \"{\\\"supervisorName\\\":\\\"ad\\\",\\\"supervisorMobileNumber\\\":\\\"3333333333\\\"}\",\n \"auditDetails\": {\n \"createdBy\": \"56b5c31b-b843-426c-b8d5-64a4c80286aa\",\n \"createdTime\": 1683072000,\n \"lastModifiedBy\": \"56b5c31b-b843-426c-b8d5-64a4c80286aa\",\n \"lastModifiedTime\": 1683072000\n }\n },\n \"workflow\": {\n \"action\": \"CREATE\",\n \"assignes\": [],\n \"comments\": \"\"\n },\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{devAuth}}\",\n \"userInfo\": {\n \"id\": 93,\n \"uuid\": \"56b5c31b-b843-426c-b8d5-64a4c80286aa\",\n \"userName\": \"sysadmin\",\n \"name\": null,\n \"mobileNumber\": \"3989999999\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"CSR\",\n \"code\": \"CSR\",\n \"tenantId\": \"default\"\n },\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"default\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"default\",\n \"permanentCity\": null\n },\n \"msgId\": \"1683093762211|en_MZ\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{dev}}/pgr-services/v2/request/_create", + "host": [ + "{{dev}}" + ], + "path": [ + "pgr-services", + "v2", + "request", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "pgr update", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{devAuth}}\",\n \"userInfo\": {\n \"id\": 23287,\n \"uuid\": \"4632c941-cb1e-4b83-b2d4-200022c1a137\",\n \"userName\": \"PalashS\",\n \"name\": \"Palash S\",\n \"mobileNumber\": \"9949032246\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"PGR Last Mile Employee\",\n \"code\": \"PGR_LME\",\n \"tenantId\": \"pb.amritsar\"\n },\n {\n \"name\": \"Employee\",\n \"code\": \"EMPLOYEE\",\n \"tenantId\": \"pb\"\n },\n {\n \"name\": \"Employee\",\n \"code\": \"EMPLOYEE\",\n \"tenantId\": \"pb.amritsar\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"pb.amritsar\"\n }\n },\n \"service\": {\n \"active\": true,\n \"user\": {\n \"id\": 29678,\n \"userName\": \"9916210028\",\n \"name\": \"Vinoth Rallapalli\",\n \"type\": \"CITIZEN\",\n \"mobileNumber\": \"9916210028\",\n \"emailId\": \"ddd@fff.com\",\n \"roles\": [\n {\n \"id\": null,\n \"name\": \"Citizen\",\n \"code\": \"CITIZEN\",\n \"tenantId\": \"pb\"\n },\n {\n \"id\": null,\n \"name\": \"BPA Town Planner\",\n \"code\": \"BPA_TOWNPLANNER\",\n \"tenantId\": \"pb\"\n }\n ],\n \"tenantId\": \"pb\",\n \"uuid\": \"47babcd6-2823-43c2-a64f-bf146b6c408d\",\n \"active\": true\n },\n \"id\": \"a8143375-bd9b-4eea-bf45-68996f676fc9\",\n \"tenantId\": \"pb.amritsar\",\n \"serviceCode\": \"OverflowingOrBlockedDrain\",\n \"serviceRequestId\": \"PB-PGR-2021-09-14-001175\",\n \"description\": \"overflowing drain\",\n \"accountId\": \"47babcd6-2823-43c2-a64f-bf146b6c408d\",\n \"rating\": null,\n \"additionalDetail\": {\n \"sdsadsadsad\": \"asdsadsadsadsa\"\n },\n \"applicationStatus\": \"PENDINGFORASSIGNMENT\",\n \"source\": \"whatsapp\",\n \"address\": {\n \"tenantId\": \"pb.amritsar\",\n \"doorNo\": \"2\",\n \"plotNo\": \"10\",\n \"id\": \"c073f0eb-c8bd-484b-ae20-d7c87321bec0\",\n \"landmark\": \"Near City Hall\",\n \"city\": \"Amritsar\",\n \"district\": \"Amritsar\",\n \"region\": \"Amritsar\",\n \"state\": \"Punjab\",\n \"country\": \"India\",\n \"pincode\": \"111111\",\n \"additionDetails\": null,\n \"buildingName\": \"Safalya\",\n \"street\": \"10th main\",\n \"locality\": {\n \"code\": \"SUN01\",\n \"name\": null,\n \"label\": null,\n \"latitude\": null,\n \"longitude\": null,\n \"children\": null,\n \"materializedPath\": null\n },\n \"geoLocation\": {\n \"latitude\": 21.0,\n \"longitude\": 56.0,\n \"additionalDetails\": null\n }\n },\n \"auditDetails\": {\n \"createdBy\": \"47babcd6-2823-43c2-a64f-bf146b6c408d\",\n \"lastModifiedBy\": \"47babcd6-2823-43c2-a64f-bf146b6c408d\",\n \"createdTime\": 1631603018031,\n \"lastModifiedTime\": 1631603018031\n }\n },\n \"workflow\": {\n \"action\": \"ASSIGN\",\n \"assignes\": [\"4632c941-cb1e-4b83-b2d4-200022c1a137\"],\n \"comments\": \"Drain Overflowing. Please check\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{dev}}/pgr-services/v2/request/_update", + "host": [ + "{{dev}}" + ], + "path": [ + "pgr-services", + "v2", + "request", + "_update" + ], + "query": [ + { + "key": null, + "value": "", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "count API", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"ver\": \".01\",\n \"action\": \"\",\n \"did\": \"1\",\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"authToken\": \"{{devAuth}}\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{dev}}/pgr-services/v2/request/_count?tenantId=pb.amritsar&applicationStatus=REJECTED", + "host": [ + "{{dev}}" + ], + "path": [ + "pgr-services", + "v2", + "request", + "_count" + ], + "query": [ + { + "key": "tenantId", + "value": "pb.amritsar" + }, + { + "key": "serviceCode", + "value": "StreetLightNotWorking", + "disabled": true + }, + { + "key": "applicationStatus", + "value": "REJECTED" + } + ] + } + }, + "response": [] + }, + { + "name": "pgr old plain search", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"ver\": \".01\",\n \"action\": \"\",\n \"did\": \"1\",\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"authToken\": \"{{devAuth}}\",\n \"userInfo\": {\n \"id\": 23349,\n \"userName\": \"9404052047\",\n \"salutation\": null,\n \"name\": \"at\",\n \"gender\": \"MALE\",\n \"mobileNumber\": \"9404052047\",\n \"emailId\": \"xc@gmail.com\",\n \"altContactNumber\": null,\n \"pan\": null,\n \"aadhaarNumber\": null,\n \"permanentAddress\": \",,,lucknow,lucknow\",\n \"permanentCity\": \"jalandhar\",\n \"permanentPinCode\": \"343434\",\n \"correspondenceAddress\": \"address \",\n \"correspondenceCity\": null,\n \"correspondencePinCode\": null,\n \"active\": true,\n \"locale\": null,\n \"type\": \"CITIZEN\",\n \"accountLocked\": false,\n \"accountLockedDate\": 0,\n \"fatherOrHusbandName\": \"st\",\n \"signature\": null,\n \"bloodGroup\": null,\n \"photo\": null,\n \"identificationMark\": null,\n \"createdBy\": 23311,\n \"lastModifiedBy\": 1,\n \"tenantId\": \"pb\",\n \"roles\": [\n {\n \"code\": \"CITIZEN\",\n \"name\": \"Citizen\",\n \"tenantId\": \"pb\"\n }\n ],\n \"uuid\": \"530968f3-76b3-4fd1-b09d-9e22eb1f85df\",\n \"createdDate\": \"05-07-2018 11:42:01\",\n \"lastModifiedDate\": \"25-03-2020 01:47:14\",\n \"dob\": \"1993-02-25\",\n \"pwdExpiryDate\": \"04-10-2018 04:12:00\"\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{local}}/rainmaker-pgr/v1/requests/_plainsearch?offset=0&noOfRecords=10&tenantId=pb.phagwara", + "host": [ + "{{local}}" + ], + "path": [ + "rainmaker-pgr", + "v1", + "requests", + "_plainsearch" + ], + "query": [ + { + "key": "offset", + "value": "0" + }, + { + "key": "noOfRecords", + "value": "10" + }, + { + "key": "tenantId", + "value": "pb.phagwara" + } + ] + } + }, + "response": [] + }, + { + "name": "transform", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"ResponseInfo\": {\n \"apiId\": \"Rainmaker\",\n \"ver\": \".01\",\n \"ts\": null,\n \"resMsgId\": \"uief87324\",\n \"msgId\": \"20170310130900|en_IN\",\n \"status\": \"successful\"\n },\n \"services\": [\n {\n \"citizen\": {\n \"id\": 23914,\n \"uuid\": \"206f4c7b-ab04-4730-acc7-4aa0d29506e6\",\n \"name\": \"name .updat\",\n \"mobileNumber\": \"9987106368\",\n \"aadhaarNumber\": null,\n \"pan\": null,\n \"emailId\": \"xvyz@gmail.com\",\n \"userName\": \"9987106368\",\n \"password\": null,\n \"active\": true,\n \"type\": \"CITIZEN\",\n \"gender\": \"MALE\",\n \"tenantId\": \"pb\",\n \"permanentAddress\": \"PB_AMRITSAR_REVENUE_SUN18, amritsar\",\n \"roles\": [\n {\n \"name\": \"Citizen\",\n \"code\": \"CITIZEN\",\n \"tenantId\": \"pb\"\n }\n ]\n },\n \"tenantId\": \"pb.jalandhar\",\n \"serviceCode\": \"DamagedGarbageBin\",\n \"serviceRequestId\": \"04/03/2020/006099\",\n \"description\": \"3\",\n \"addressId\": \"da8af2cd-cdfa-489e-8828-bce515d41f61\",\n \"accountId\": \"23914\",\n \"phone\": \"9987106368\",\n \"addressDetail\": {\n \"uuid\": \"da8af2cd-cdfa-489e-8828-bce515d41f61\",\n \"mohalla\": \"JLC468\",\n \"locality\": \"GTB Nagar\",\n \"city\": \"pb.jalandhar\",\n \"tenantId\": \"pb.jalandhar\"\n },\n \"active\": true,\n \"status\": \"assigned\",\n \"source\": \"whatsapp\",\n \"auditDetails\": {\n \"createdBy\": \"23914\",\n \"lastModifiedBy\": \"23370\",\n \"createdTime\": 1583314541457,\n \"lastModifiedTime\": 1583327412746\n }\n }\n ],\n \"actionHistory\": [\n {\n \"actions\": [\n {\n \"uuid\": \"261f5bea-b293-493c-8572-d4af6b807981\",\n \"tenantId\": \"pb.jalandhar\",\n \"by\": \"23370:GRO\",\n \"when\": 1583327412746,\n \"businessKey\": \"04/03/2020/006099\",\n \"action\": \"assign\",\n \"status\": \"assigned\",\n \"assignee\": \"28258\"\n },\n {\n \"uuid\": \"6c87870a-48ce-4d1d-9fa8-a8649a6e9add\",\n \"tenantId\": \"pb.jalandhar\",\n \"by\": \"23370:GRO\",\n \"when\": 1583327361714,\n \"businessKey\": \"04/03/2020/006099\",\n \"comments\": \"dff\"\n },\n {\n \"uuid\": \"b78255ef-333a-4419-bbbb-962becaa2a5c\",\n \"tenantId\": \"pb.jalandhar\",\n \"by\": \"23914:BPA Architect\",\n \"when\": 1583314541457,\n \"businessKey\": \"04/03/2020/006099\",\n \"action\": \"open\",\n \"status\": \"open\",\n \"media\": [\n \"https://minio-egov-micro-dev.egovernments.org/egov-rainmaker/pb/chatbot/March/4/1583314533928pgr-whatsapp-1583314533825.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20201014%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20201014T052552Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=360c179db1c6d21e95146a31a1b68a39b09e7b96e15cc881357289dac89e8771,https://minio-egov-micro-dev.egovernments.org/egov-rainmaker/pb/chatbot/March/4/1583314533928pgr-whatsapp-1583314533825_large.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20201014%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20201014T052552Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=3188d9d15e1ff94e459cdcef93c116621a26bb34f9b89183192273ebd8b97981,https://minio-egov-micro-dev.egovernments.org/egov-rainmaker/pb/chatbot/March/4/1583314533928pgr-whatsapp-1583314533825_medium.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20201014%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20201014T052552Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=681373c0758c92a6d00e30ef2c36ff58384de030c021599908305909ca70e79e,https://minio-egov-micro-dev.egovernments.org/egov-rainmaker/pb/chatbot/March/4/1583314533928pgr-whatsapp-1583314533825_small.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20201014%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20201014T052552Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=89eab9c8e2e3fdff1039d0a95fce4fce1f3c5d2c6248b9577877a52d14565fc1\"\n ]\n }\n ]\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{local}}/pgr-services/migration/_transform", + "host": [ + "{{local}}" + ], + "path": [ + "pgr-services", + "migration", + "_transform" + ] + } + }, + "response": [] + }, + { + "name": "pgr migration", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{devAuth}}\",\n \"userInfo\": {\n \"id\": 23287,\n \"uuid\": \"4632c941-cb1e-4b83-b2d4-200022c1a137\",\n \"userName\": \"PalashS\",\n \"name\": \"Palash S\",\n \"mobileNumber\": \"9949032246\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"PGR Last Mile Employee\",\n \"code\": \"PGR_LME\",\n \"tenantId\": \"pb.amritsar\"\n },\n {\n \"name\": \"Employee\",\n \"code\": \"EMPLOYEE\",\n \"tenantId\": \"pb\"\n },\n {\n \"name\": \"Employee\",\n \"code\": \"EMPLOYEE\",\n \"tenantId\": \"pb.amritsar\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"pb.amritsar\"\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8083/rainmaker-pgr/v2/_migrate?tenantIds=pb.bathinda&serviceRequestIds=17/12/2018/005891", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8083", + "path": [ + "rainmaker-pgr", + "v2", + "_migrate" + ], + "query": [ + { + "key": "tenantIds", + "value": "pb.bathinda" + }, + { + "key": "serviceRequestIds", + "value": "17/12/2018/005891" + } + ] + } + }, + "response": [] + } + ] +} \ No newline at end of file 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 6dfbc669431..5b5bfe71423 100644 --- a/core-services/service-request/pom.xml +++ b/core-services/service-request/pom.xml @@ -4,7 +4,7 @@ service-request jar service-request - 1.0.0 + 1.0.1 1.8 ${java.version} @@ -41,13 +41,14 @@ spring-boot-starter-jdbc - org.flywaydb - flyway-core + org.flywaydb + flyway-core + 9.22.3 - org.postgresql - postgresql - 42.2.2.jre7 + org.postgresql + postgresql + 42.7.1 org.springframework.boot diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java b/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java index fc692f42310..66595568bc1 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java @@ -104,6 +104,9 @@ private void validateAttributeValuesAgainstServiceDefinition(ServiceDefinition s // Validate if value being passed is consistent in terms of data type provided as part of service definition service.getAttributes().forEach(attributeValue -> { + if (attributeValue.getValue() == null && !setOfRequiredAttributes.contains(attributeValue.getAttributeCode())) { + return; + } if(attributeCodeVsDataType.get(attributeValue.getAttributeCode()).equals(AttributeDefinition.DataTypeEnum.NUMBER)){ if(!(attributeValue.getValue() instanceof Number)){ throw new CustomException(SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_CODE, SERVICE_REQUEST_ATTRIBUTE_INVALID_NUMBER_VALUE_MSG); @@ -135,6 +138,9 @@ private void validateAttributeValuesAgainstServiceDefinition(ServiceDefinition s // Validate if value provided against attribute definition of single value list and multi value list is the same as the list of values provided during creation service.getAttributes().forEach(attributeValue -> { + if (attributeValue.getValue() == null && !setOfRequiredAttributes.contains(attributeValue.getAttributeCode())) { + return; + } if(attributeCodeVsValues.containsKey(attributeValue.getAttributeCode())){ if(attributeCodeVsDataType.get(attributeValue.getAttributeCode()).equals(AttributeDefinition.DataTypeEnum.SINGLEVALUELIST)){ if(!attributeCodeVsValues.get(attributeValue.getAttributeCode()).contains(attributeValue.getValue())){ diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java index cefb96adac8..59c32cf913b 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java @@ -60,7 +60,9 @@ public enum DataTypeEnum { MULTIVALUELIST("MultiValueList"), - FILE("File"); + FILE("File"), + + BOOLEAN("Boolean"); private String value; diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java index 8b498387d86..8aeff4e39f3 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java @@ -35,7 +35,6 @@ public class AttributeValue { private String attributeCode = null; @JsonProperty("value") - @NotNull private Object value = null; @JsonProperty("auditDetails") diff --git a/core-services/service-request/src/main/resources/db/Dockerfile b/core-services/service-request/src/main/resources/db/Dockerfile index 60fc07ce69f..e7da01d7f0b 100644 --- a/core-services/service-request/src/main/resources/db/Dockerfile +++ b/core-services/service-request/src/main/resources/db/Dockerfile @@ -1,4 +1,4 @@ -FROM egovio/flyway:4.1.2 +FROM egovio/flyway:10.7.1 COPY ./migration/main /flyway/sql @@ -6,4 +6,4 @@ COPY migrate.sh /usr/bin/migrate.sh RUN chmod +x /usr/bin/migrate.sh -CMD ["/usr/bin/migrate.sh"] \ No newline at end of file +ENTRYPOINT ["/usr/bin/migrate.sh"] \ No newline at end of file diff --git a/core-services/service-request/src/main/resources/db/migrate.sh b/core-services/service-request/src/main/resources/db/migrate.sh index 43960b25cdb..f9d6617822c 100644 --- a/core-services/service-request/src/main/resources/db/migrate.sh +++ b/core-services/service-request/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/docs/health-api-specs/contracts/complaints-v2.yaml b/docs/health-api-specs/contracts/complaints-v2.yaml new file mode 100644 index 00000000000..0329de1a1d3 --- /dev/null +++ b/docs/health-api-specs/contracts/complaints-v2.yaml @@ -0,0 +1,570 @@ +openapi: 3.0.1 +info: + version: v2 + title: DIGIT Public Grievance Redressal(PGR) V2 + description: | + ### API specs for PGR ### + Application to Raise Grivances and track the progress. + . It allows any user registered in the system to raise a complaint (based on the Service definition provided in the master data, Please Refer MDMS service to Service Definition master) for any ulb belonging to the state. + . Notifications will be provided on progress of the complaint in evevry step. + . Feedback can be provided by the user once the compliant is resolved. + . If not satisfied the user can reopen the complaint. +paths: + + /v2/request/_search: + post: + tags: + - requests-api-controller + operationId: requestsSearchPost + requestBody: + content: + application/json: + schema: + type: object + properties: + requestInfoWrapper: + $ref: '#/components/schemas/RequestInfoWrapper' + criteria: + $ref: '#/components/schemas/RequestSearchCriteria' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ServiceResponse' + /v2/request/_plainsearch: + post: + tags: + - requests-api-controller + operationId: requestsPlainSearchPost + requestBody: + content: + application/json: + schema: + type: object + properties: + requestInfoWrapper: + $ref: '#/components/schemas/RequestInfoWrapper' + requestSearchCriteria: + $ref: '#/components/schemas/RequestSearchCriteria' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ServiceResponse' + /v2/request/_create: + post: + tags: + - requests-api-controller + operationId: requestsCreatePost + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ServiceRequest' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ServiceResponse' + /v2/request/_update: + post: + tags: + - requests-api-controller + operationId: requestsUpdatePost + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ServiceRequest' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ServiceResponse' + /v2/request/_count: + post: + tags: + - requests-api-controller + operationId: requestsCountPost + requestBody: + content: + application/json: + schema: + type: object + properties: + requestInfoWrapper: + $ref: '#/components/schemas/RequestInfoWrapper' + criteria: + $ref: '#/components/schemas/RequestSearchCriteria' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/CountResponse' + /migration/_transform: + post: + tags: + - migration-controller + operationId: requestsCreatePost_1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ServiceResponse' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + additionalProperties: + type: object +components: + schemas: + Address: + type: object + properties: + tenantId: + type: string + description: Unique Identifier of the tenant to which user primarily belongs + doorNo: + type: string + description: House number or door number. + plotNo: + type: string + description: Plot number of the house. + id: + type: string + description: System generated id for the address + readOnly: true + landmark: + type: string + description: additional landmark to help locate the address + city: + type: string + description: City of the address. Can be represented by the tenantid itself + district: + type: string + description: The district in which the property is located + region: + type: string + description: The Region in which the property is located + state: + type: string + description: The State in which the property is located + country: + type: string + description: The Country in which the property is located + pincode: + type: string + description: PIN code of the address. Indian pincodes will usually be all numbers. + additionDetails: + type: object + description: more address detail as may be needed + buildingName: + type: string + description: Name of the building + maxLength: 64 + minLength: 2 + street: + type: string + description: Street Name + maxLength: 64 + minLength: 2 + locality: + $ref: '#/components/schemas/Boundary' + geoLocation: + $ref: '#/components/schemas/GeoLocation' + AuditDetails: + type: object + properties: + createdBy: + type: string + description: username (preferred) or userid of the user that created the object + lastModifiedBy: + type: string + description: username (preferred) or userid of the user that last modified the object + createdTime: + type: integer + format: int64 + description: epoch of the time object is created + lastModifiedTime: + type: integer + format: int64 + description: epoch of the time object is last modified + Boundary: + required: + - code + type: object + properties: + code: + type: string + description: code of the boundary. + name: + type: string + description: name of the boundary. + label: + type: string + description: localized label for the boundry. + latitude: + type: string + description: latitude of the boundary. + longitude: + type: string + description: longitude of the boundary. + children: + type: array + items: + $ref: '#/components/schemas/Boundary' + materializedPath: + type: string + description: materialized path of the boundary - this would be of the format tenantid.[code] from parentt till teh current boundary + Document: + type: object + description: This object holds list of documents attached during the transaciton for a property + properties: + id: + type: string + description: system id of the Document. + maximum: 64 + documentType: + type: string + description: unique document type code, should be validated with document type master + fileStoreId: + type: string + description: File store reference key. + documentUid: + type: string + description: The unique id(Pancard Number,Adhar etc.) of the given Document. + maxLength: 64 + additionalDetails: + type: object + description: The unique id(Pancard Number,Adhar etc.) of the given Document. + GeoLocation: + type: object + properties: + latitude: + type: number + format: double + description: latitude of the address + longitude: + type: number + format: double + description: longitude of the address + additionalDetails: + type: object + RequestInfo: + type: object + properties: + apiId: + type: string + ver: + type: string + ts: + type: integer + format: int64 + description: time in epoch + action: + type: string + description: API action to be performed like _create, _update, _search (denoting POST, PUT, GET) or _oauth etc + maxLength: 32 + did: + type: string + key: + type: string + description: API key (API key provided to the caller in case of server to server communication) + maxLength: 256 + msgId: + type: string + description: Unique request message id from the caller + maxLength: 256 + authToken: + type: string + description: token - the usual value that would go into HTTP bearer token + correlationId: + type: string + readOnly: true + userInfo: + $ref: '#/components/schemas/User' + Role: + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + code: + type: string + tenantId: + type: string + Service: + required: + - address + - serviceCode + - source + - tenantId + type: object + properties: + active: + type: boolean + user: + $ref: '#/components/schemas/User' + id: + type: string + tenantId: + type: string + description: Unique identifier of the tenant. + minLength: 2 + maxLength: 64 + serviceCode: + type: string + description: Unique Code of the service defination (from service defination master) + minLength: 2 + maxLength: 64 + serviceRequestId: + type: string + readOnly: true + description: The unique formatted id for service request. + minLength: 2 + maxLength: 128 + description: + type: string + description: Additional information or description of the service request + minLength: 2 + maxLength: 256 + accountId: + type: string + description: userid of the user requesting the srervice - in our case it may be same as phone as we are using mobile number as the userid + minLength: 2 + maxLength: 64 + rating: + maximum: 5 + minimum: 1 + type: integer + format: int32 + additionalDetail: + type: object + description: This is the json object that will carry the actual input (whereever the metadata requries input). Structure should be same as the schema definition provided in the metadata of the service (schema compliance check to be performed at client/server) + applicationStatus: + type: string + description: The current status of the service request. + readOnly: true + source: + type: string + description: 'Source mdms master data. Which captures the source of the service request(ex:- whatsapp, ivr, Swachhata etc)' + minLength: 2 + maxLength: 64 + example: whatsapp, ivr etc + address: + $ref: '#/components/schemas/Address' + auditDetails: + $ref: '#/components/schemas/AuditDetails' + selfComplaint: + type: boolean + ServiceRequest: + required: + - RequestInfo + type: object + properties: + RequestInfo: + $ref: '#/components/schemas/RequestInfo' + service: + $ref: '#/components/schemas/Service' + workflow: + $ref: '#/components/schemas/Workflow' + User: + type: object + description: This is acting ID token of the authenticated user on the server. Any value provided by the clients will be ignored and actual user based on authtoken will be used on the server. + properties: + id: + type: integer + format: int64 + userName: + type: string + description: Unique user name of the authenticated user + name: + type: string + type: + type: string + mobileNumber: + type: string + emailId: + type: string + roles: + type: array + items: + $ref: '#/components/schemas/Role' + tenantId: + type: string + description: Unique Identifier of the tenant to which user primarily belongs + uuid: + type: string + description: System Generated User id of the authenticated user. + active: + type: boolean + Workflow: + type: object + description: BPA application object to capture the details of land, land owners, and address of the land. + properties: + action: + type: string + description: Action on the application in certain + minLength: 1 + maxLength: 64 + assignes: + type: array + + items: + type: string + comments: + type: string + description: Unique Identifier scrutinized number + minLength: 1 + maxLength: 64 + verificationDocuments: + type: array + description: Attach the workflow varification documents. + items: + $ref: '#/components/schemas/Document' + ResponseInfo: + type: object + properties: + apiId: + type: string + ver: + type: string + ts: + type: integer + format: int64 + resMsgId: + type: string + msgId: + type: string + status: + type: string + ServiceResponse: + type: object + properties: + responseInfo: + $ref: '#/components/schemas/ResponseInfo' + ServiceWrappers: + type: array + items: + $ref: '#/components/schemas/ServiceWrapper' + complaintsResolved: + type: integer + format: int32 + averageResolutionTime: + type: integer + format: int32 + complaintTypes: + type: integer + format: int32 + ServiceWrapper: + type: object + properties: + service: + $ref: '#/components/schemas/Service' + workflow: + $ref: '#/components/schemas/Workflow' + RequestInfoWrapper: + type: object + properties: + RequestInfo: + $ref: '#/components/schemas/RequestInfo' + RequestSearchCriteria: + type: object + properties: + empty: + type: boolean + tenantId: + type: string + tenantIds: + uniqueItems: true + type: array + items: + type: string + serviceCode: + uniqueItems: true + type: array + items: + type: string + applicationStatus: + uniqueItems: true + type: array + items: + type: string + mobileNumber: + type: string + serviceRequestId: + readOnly: true + description: The unique formatted id for service request. + minLength: 2 + maxLength: 128 + sortBy: + type: string + enum: + - locality + - applicationStatus + - serviceRequestId + sortOrder: + type: string + enum: + - ASC + - DESC + locality: + uniqueItems: true + type: array + items: + type: string + ids: + uniqueItems: true + type: array + items: + type: string + fromDate: + type: integer + format: int64 + toDate: + type: integer + format: int64 + slaDeltaMaxLimit: + type: integer + format: int64 + slaDeltaMinLimit: + type: integer + format: int64 + limit: + type: integer + format: int32 + offset: + type: integer + format: int32 + accountId: + type: string + CountResponse: + type: object + properties: + ResponseInfo: + $ref: '#/components/schemas/ResponseInfo' + count: + type: integer + format: int32 \ No newline at end of file diff --git a/docs/health-api-specs/contracts/project.yml b/docs/health-api-specs/contracts/project.yml index 08f9427db15..7f61b66324e 100644 --- a/docs/health-api-specs/contracts/project.yml +++ b/docs/health-api-specs/contracts/project.yml @@ -174,7 +174,7 @@ paths: schema: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - + /project/beneficiary/v1/bulk/_update: post: @@ -1413,6 +1413,10 @@ definitions: minLength: 2 maxLength: 64 description: Client maintained unique ID of Household/Individual being added as beneficiary + tag: + type: string + maxLength: 1000 + description: Beneficiary Voucher Tag dateOfRegistration: $ref: '#/definitions/eventTimestamp' additionalFields: @@ -1434,12 +1438,16 @@ definitions: clientReferenceId: $ref: '#/definitions/clientReferenceIdForSearch' projectId: - type: string + type: array + items: + type: string minLength: 2 maxLength: 64 description: Unique ID form Project beneficiaryId: - type: string + type: array + items: + type: string minLength: 2 maxLength: 64 description: Unique ID of Household/Individual being added as beneficiary @@ -1529,13 +1537,17 @@ definitions: clientReferenceId: $ref: '#/definitions/clientReferenceIdForSearch' projectId: - type: string + type: array + items: + type: string minLength: 2 maxLength: 64 description: Unique ProjectId projectBeneficiaryId: - type: string - example: "R-ID-1" + type: array + items: + type: string + example: "R-ID-1" plannedStartDate: type: integer format: int64 @@ -1618,12 +1630,16 @@ definitions: id: $ref: '#/definitions/idForSearch' staffId: - type: string + type: array + items: + type: string description: Unique userId defined using user service minLength: 2 maxLength: 64 projectId: - type: string + type: array + items: + type: string description: Project Id minLength: 2 maxLength: 64 @@ -1726,7 +1742,9 @@ definitions: id: $ref: '#/definitions/idForSearch' projectId: - type: string + type: array + items: + type: string description: Unique Project Id defined in Project Service minLength: 2 maxLength: 64 @@ -1821,7 +1839,7 @@ definitions: RequestInfo: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo - Project: + Projects: type: array minItems: 1 items: @@ -1848,7 +1866,7 @@ definitions: ResponseInfo: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo - Project: + Projects: type: array items: $ref: '#/definitions/Project' diff --git a/docs/health-api-specs/contracts/referral-management.yml b/docs/health-api-specs/contracts/referral-management.yml new file mode 100644 index 00000000000..af73191c0e1 --- /dev/null +++ b/docs/health-api-specs/contracts/referral-management.yml @@ -0,0 +1,810 @@ +swagger: '2.0' +info: + version: 1.0.0 + title: Referral Management System + contact: + name: egovernments foundation + email: info@egovernments.org +schemes: + - https +x-common-path: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-0-0.yml +paths: + /referralmanagement/beneficiary-downsync/v1/_get: + post: + summary: Downsync beneficiary details for a Project + description: when data created by a different registar needs to be downsynced by another registar/device, this api will serve as a one point search for benefeiciary details + parameters: + - name: Downsync + in: body + description: Downsync of registry based on area. + required: true + schema: + $ref: '#/definitions/DownsyncRequest' + tags: + - Beneficiary Downsync + responses: + '200': + description: Downsync. + schema: + $ref: '#/definitions/DownsyncResponse' + '400': + description: Invalid Input body. + schema: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + /referralmanagement/side-effect/v1/_create: + post: + summary: Create side effect for the project + description: Create side effect for the project + parameters: + - name: SideEffect + in: body + description: Capture details of Side Effect + required: true + schema: + $ref: '#/definitions/SideEffectRequest' + tags: + - Side Effect + responses: + '202': + description: Create side effect request has been accepted for creation. + schema: + $ref: '#/definitions/SideEffectResponse' + '400': + description: Invalid Input body. + schema: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + /referralmanagement/side-effect/v1/bulk/_create: + post: + summary: Create side effects for the project in bulk + description: Create side effects for the project in bulk + parameters: + - name: SideEffect + in: body + description: Capture details of Task + required: true + schema: + $ref: '#/definitions/SideEffectBulkRequest' + tags: + - Side Effect + responses: + '202': + description: Create side effect request has been accepted for creation. + schema: + $ref: '#/definitions/BulkAcceptedResponse' + '400': + description: Invalid Input body. + schema: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + /referralmanagement/side-effect/v1/_update: + post: + summary: Side Effect Request + description: Side Effect Request + parameters: + - name: SideEffect + in: body + description: Capture details of Existing side effect + required: true + schema: + $ref: '#/definitions/SideEffectRequest' + tags: + - Side Effect + responses: + '202': + description: update side effect request has been accepted for update. + schema: + $ref: '#/definitions/SideEffectResponse' + '400': + description: Invalid Input body. + schema: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + /referralmanagement/side-effect/v1/bulk/_update: + post: + summary: Side Effect Request in bulk for a project + description: Side Effect Request in bulk for a project + parameters: + - name: SideEffect + in: body + description: Capture details of Existing Side Effects + required: true + schema: + $ref: '#/definitions/SideEffectBulkRequest' + tags: + - Side Effect + responses: + '202': + description: update Side Effects bulk request has been accepted for update. + schema: + $ref: '#/definitions/BulkAcceptedResponse' + '400': + description: Invalid Input body. + schema: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + /referralmanagement/side-effect/v1/_delete: + post: + summary: Soft delete Side Effect for a project + description: Soft delete Side Effect for a project + parameters: + - name: SideEffect + in: body + description: Capture details of Existing Side Effect + required: true + schema: + $ref: '#/definitions/SideEffectRequest' + tags: + - Side Effect + responses: + '202': + description: delete Side Effect request has been accepted for deletion. + schema: + $ref: '#/definitions/SideEffectResponse' + '400': + description: Invalid Input body. + schema: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + /referralmanagement/side-effect/v1/bulk/_delete: + post: + summary: Soft delete Side Effects for a project + description: Soft delete Side Effects for a project + parameters: + - name: SideEffect + in: body + description: Capture details of Existing Side Effect + required: true + schema: + $ref: '#/definitions/SideEffectRequest' + tags: + - Side Effect + responses: + '202': + description: delete bulk Side Effect request has been accepted for deletion. + schema: + $ref: '#/definitions/BulkAcceptedResponse' + '400': + description: Invalid Input body. + schema: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + /referralmanagement/side-effect/v1/_search: + post: + summary: Search Side Effect for Project + description: Search Side Effect for Project + parameters: + - name: SideEffect + in: body + description: Side Effect Search. + required: true + schema: + $ref: '#/definitions/SideEffectSearchRequest' + - $ref: '#/parameters/limit' + - $ref: '#/parameters/offset' + - $ref: '#/parameters/tenantId' + - $ref: '#/parameters/lastChangedSince' + - $ref: '#/parameters/includeDeleted' + tags: + - Side Effect + responses: + '200': + description: Side Effects. + schema: + $ref: '#/definitions/SideEffectBulkResponse' + '400': + description: Invalid Input body. + schema: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + /referralmanagement/v1/_create: + post: + summary: Create referral for the project beneficiary + description: Create referral for the project benefiaciary + parameters: + - name: Referral + in: body + description: Capture details of Referral + required: true + schema: + $ref: '#/definitions/ReferralRequest' + tags: + - Referral + responses: + '202': + description: Create referral request has been accepted for creation. + schema: + $ref: '#/definitions/ReferralResponse' + '400': + description: Invalid Input body. + schema: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + /referralmanagement/v1/bulk/_create: + post: + summary: Create referrals for the project beneficiary in bulk + description: Create referrals for the project beneficiary in bulk + parameters: + - name: Referral + in: body + description: Capture details of Task + required: true + schema: + $ref: '#/definitions/ReferralBulkRequest' + tags: + - Referral + responses: + '202': + description: Create referral request has been accepted for creation. + schema: + $ref: '#/definitions/BulkAcceptedResponse' + '400': + description: Invalid Input body. + schema: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + /referralmanagement/v1/_update: + post: + summary: Referral Request + description: Referral Request + parameters: + - name: Referral + in: body + description: Capture details of Existing referral + required: true + schema: + $ref: '#/definitions/ReferralRequest' + tags: + - Referral + responses: + '202': + description: update referral request has been accepted for update. + schema: + $ref: '#/definitions/ReferralResponse' + '400': + description: Invalid Input body. + schema: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + /referralmanagement/v1/bulk/_update: + post: + summary: Referral Request in bulk for a project beneficiary + description: Referral Request in bulk for a project beneficiary + parameters: + - name: Referral + in: body + description: Capture details of Existing Referrals + required: true + schema: + $ref: '#/definitions/ReferralBulkRequest' + tags: + - Referral + responses: + '202': + description: update Referrals bulk request has been accepted for update. + schema: + $ref: '#/definitions/BulkAcceptedResponse' + '400': + description: Invalid Input body. + schema: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + /referralmanagement/v1/_delete: + post: + summary: Soft delete Referral for a project beneficiary + description: Soft delete Referral for a project beneficiary + parameters: + - name: Referral + in: body + description: Capture details of Existing Referral + required: true + schema: + $ref: '#/definitions/ReferralRequest' + tags: + - Referral + responses: + '202': + description: delete Referral request has been accepted for deletion. + schema: + $ref: '#/definitions/ReferralResponse' + '400': + description: Invalid Input body. + schema: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + /referralmanagement/v1/bulk/_delete: + post: + summary: Soft delete Referrals for a project beneficiary + description: Soft delete Referrals for a project beneficiary + parameters: + - name: Referral + in: body + description: Capture details of Existing Referral + required: true + schema: + $ref: '#/definitions/ReferralRequest' + tags: + - Referral + responses: + '202': + description: delete bulk Referral request has been accepted for deletion. + schema: + $ref: '#/definitions/BulkAcceptedResponse' + '400': + description: Invalid Input body. + schema: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + /referralmanagement/v1/_search: + post: + summary: Search Referral for Project + description: Search Referral for Project + parameters: + - name: Referral + in: body + description: Referral Search. + required: true + schema: + $ref: '#/definitions/ReferralSearchRequest' + - $ref: '#/parameters/limit' + - $ref: '#/parameters/offset' + - $ref: '#/parameters/tenantId' + - $ref: '#/parameters/lastChangedSince' + - $ref: '#/parameters/includeDeleted' + tags: + - Referral + responses: + '200': + description: Referrals. + schema: + $ref: '#/definitions/ReferralBulkResponse' + '400': + description: Invalid Input body. + schema: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + +parameters: + tenantId: + name: tenantId + in: query + description: Unique id for a tenant. + required: true + type: string + format: varchar + lastChangedSince: + name: lastChangedSince + description: | + epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. + in: query + required: false + type: integer + format: int64 + echoResource: + name: echoResource + in: query + type: boolean + required: false + default: true + description: Client can specify if the resource in request body needs to be sent back in the response. This is being used to limit amount of data that needs to flow back from the server to the client in low bandwidth scenarios. Server will always send the server generated id for validated requests. + serverHandlesErrors: + name: serverHandlesErrors + in: query + type: boolean + required: false + default: false + description: Client can specify that it is incapable of handling any errors with the requests and server should route these for manual intervention if required. + limit: + name: limit + description: Pagination - limit records in response + in: query + type: integer + minimum: 0 + maximum: 1000 + required: true + offset: + name: offset + description: Pagination - offset from which records should be returned in response + in: query + type: integer + minimum: 0 + required: true + includeDeleted: + name: includeDeleted + description: Used in search APIs to specify if (soft) deleted records should be included in search results. + in: query + type: boolean + default: false + required: false + includeEnded: + name: includeEnded + description: Used in project search API to specify if records past end date should be included in search results. + in: query + type: boolean + default: false + required: false + includeAncestors: + name: includeAncestors + description: Used in project search API to specify if response should include project elements that are in the preceding hierarchy of matched projects. + in: query + type: boolean + default: false + required: false + includeDescendants: + name: includeDescendants + description: Used in project search API to specify if response should include project elements that are in the following hierarchy of matched projects. + in: query + type: boolean + default: false + required: false + createdFrom: + name: createdFrom + description: | + Used in project search API to limit the search results to only those projects whose creation date is after the specified 'createdFrom' date. + in: query + required: false + type: integer + format: int64 + createdTo: + name: createdTo + description: | + Used in project search API to limit the search results to only those projects whose creation date is before the specified 'createdTo' date. + in: query + required: false + type: integer + format: int64 +definitions: + boundaryCode: + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/boundaryCode + id: + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/id + idForSearch: + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/idForSearch + clientReferenceIdForSearch: + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/clientReferenceIdForSearch + clientReferenceId: + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/clientReferenceId + tenantId: + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/tenantId + eventTimestamp: + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/eventTimestamp + isDeleted: + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/isDeleted + rowVersion: + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/rowVersion + apiOperation: + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/apiOperation + additionalFields: + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/additionalFields + Address: + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/Address + SideEffect: + type: object + required: + - tenantId + - taskId + - symptoms + properties: + id: + $ref: '#/definitions/id' + clientReferenceId: + $ref: '#/definitions/clientReferenceId' + tenantId: + $ref: '#/definitions/tenantId' + taskId: + type: string + minLength: 2 + maxLength: 64 + description: Unique TaskId + taskClientReferenceId: + type: string + example: R-ID-1 + description: Unique Task Client Reference Id + projectBeneficiaryId: + type: string + minLength: 2 + maxLength: 64 + description: Project Beneficiary Id + projectBeneficiaryClientReferenceId: + type: string + minLength: 2 + maxLength: 64 + description: Project Beneficiary Client Reference Id + symptoms: + type: array + items: + type: string + additionalFields: + $ref: '#/definitions/additionalFields' + isDeleted: + $ref: '#/definitions/isDeleted' + rowVersion: + $ref: '#/definitions/rowVersion' + auditDetails: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails + clientAuditDetails: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails + SideEffectRequest: + type: object + properties: + RequestInfo: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + SideEffect: + type: object + $ref: '#/definitions/SideEffect' + required: + - RequestInfo + - SideEffect + SideEffectBulkRequest: + type: object + properties: + RequestInfo: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + SideEffects: + type: array + minItems: 1 + items: + $ref: '#/definitions/SideEffect' + required: + - RequestInfo + - SideEffects + SideEffectSearch: + type: object + properties: + id: + $ref: '#/definitions/idForSearch' + clientReferenceId: + $ref: '#/definitions/clientReferenceIdForSearch' + taskId: + type: array + items: + type: string + minLength: 2 + maxLength: 64 + description: Unique TaskId + taskClientReferenceId: + type: array + items: + type: string + example: R-ID-1 + SideEffectSearchRequest: + type: object + properties: + RequestInfo: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + SideEffect: + $ref: '#/definitions/SideEffectSearch' + required: + - RequestInfo + - SideEffect + SideEffectResponse: + type: object + properties: + ResponseInfo: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + SideEffect: + type: object + $ref: '#/definitions/SideEffect' + required: + - ResponseInfo + - SideEffect + SideEffectBulkResponse: + type: object + properties: + ResponseInfo: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + SideEffects: + type: array + items: + $ref: '#/definitions/SideEffect' + required: + - ResponseInfo + - SideEffects + Referral: + type: object + required: + - tenantId + properties: + id: + $ref: '#/definitions/id' + clientReferenceId: + $ref: '#/definitions/clientReferenceId' + tenantId: + $ref: '#/definitions/tenantId' + projectBeneficiaryId: + type: string + minLength: 2 + maxLength: 64 + description: Project Beneficiary Id + projectBeneficiaryClientReferenceId: + type: string + minLength: 2 + maxLength: 64 + description: Project Beneficiary Client Reference Id + referrerId: + type: string + minLength: 2 + maxLength: 64 + description: Worker Id that is referring the Beneficiary + recipientId: + type: string + minLength: 2 + maxLength: 64 + description: Individual or Facility Id whom the Beneficiary is referred to. + recipientType: + type: string + description: Individual or Facility + reasons: + type: array + items: + type: string + sideEffect: + $ref: '#/definitions/SideEffect' + additionalFields: + $ref: '#/definitions/additionalFields' + isDeleted: + $ref: '#/definitions/isDeleted' + rowVersion: + $ref: '#/definitions/rowVersion' + auditDetails: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails + clientAuditDetails: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails + ReferralRequest: + type: object + properties: + RequestInfo: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + Referral: + type: object + $ref: '#/definitions/Referral' + required: + - RequestInfo + - Referral + ReferralBulkRequest: + type: object + properties: + RequestInfo: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + Referrals: + type: array + minItems: 1 + items: + $ref: '#/definitions/Referral' + required: + - RequestInfo + - Referrals + ReferralSearch: + type: object + properties: + id: + $ref: '#/definitions/idForSearch' + clientReferenceId: + $ref: '#/definitions/clientReferenceIdForSearch' + projectBeneficiaryId: + type: array + items: + type: string + projectBeneficiaryClientReferenceId: + type: array + items: + type: string + sideEffectId: + type: array + items: + type: string + sideEffectClientReferenceId: + type: array + items: + type: string + referrerId: + type: array + items: + type: string + recipientId: + type: array + items: + type: string + + + ReferralSearchRequest: + type: object + properties: + RequestInfo: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + Referral: + $ref: '#/definitions/ReferralSearch' + required: + - RequestInfo + - Referral + ReferralResponse: + type: object + properties: + ResponseInfo: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + Referral: + type: object + $ref: '#/definitions/Referral' + required: + - ResponseInfo + - Referral + ReferralBulkResponse: + type: object + properties: + ResponseInfo: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + Referrals: + type: array + items: + $ref: '#/definitions/Referral' + required: + - ResponseInfo + - Referrals + BulkAcceptedResponse: + type: object + properties: + ResponseInfo: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + required: + - ResponseInfo + + DownsyncRequest: + type: object + properties: + RequestInfo: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + DownsyncCriteria: + $ref: '#/definitions/DownsyncCriteria' + required: + - RequestInfo + - DownsyncCriteria + DownsyncResponse: + type: object + properties: + ResponseInfo: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + Downsync: + $ref: '#/definitions/Downsync' + required: + - ResponseInfo + - Downsync + DownsyncCriteria: + type: object + properties: + locality: + type: string + description: locality/boundary code from which all beneficiary has to be downloaded + totalCount: + type: [null,long] + description: totalCount + tenantId: + $ref: '#/parameters/tenantId' + offset: + $ref: '#/parameters/offset' + limit: + $ref: '#/parameters/limit' + lastSyncedTime: + $ref: '#/parameters/lastChangedSince' + includeDeleted: + $ref: '#/parameters/includeDeleted' + Downsync: + type: object + properties: + DownsyncCriteria: + $ref: '#/definitions/DownsyncCriteria' + Households: + type: array + items: + $ref: https://raw.githubusercontent.com/egovernments/health-api-specs/main/contracts/registries/household.yml#/definitions/Household + HouseholdMembers: + type: array + items: + $ref: https://raw.githubusercontent.com/egovernments/health-api-specs/main/contracts/registries/household.yml#/definitions/HouseholdMember + Individuals: + type: array + items: + $ref: https://raw.githubusercontent.com/egovernments/health-api-specs/main/contracts/registries/individual.yml#/definitions/Individual + ProjectBeneficiaries: + type: array + items: + $ref: https://raw.githubusercontent.com/egovernments/health-api-specs/main/contracts/project.yml#/definitions/ProjectBeneficiary + Tasks: + type: array + items: + $ref: https://raw.githubusercontent.com/egovernments/health-api-specs/main/contracts/project.yml#/definitions/Task + SideEffects: + type: array + items: + $ref: '#/definitions/SideEffect' + Referrals: + type: array + items: + $ref: '#/definitions/Referral' + + diff --git a/docs/health-api-specs/contracts/registries/individual.yml b/docs/health-api-specs/contracts/registries/individual.yml index 917767ca57b..8fce191f8c4 100644 --- a/docs/health-api-specs/contracts/registries/individual.yml +++ b/docs/health-api-specs/contracts/registries/individual.yml @@ -434,6 +434,10 @@ definitions: $ref: '#/definitions/additionalFields' isDeleted: $ref: '#/definitions/isDeleted' + isSystemUser: + type: boolean + description: Flag to indicate if the individual should be registered with Egov-user service + readOnly: true rowVersion: $ref: '#/definitions/rowVersion' auditDetails: @@ -444,7 +448,10 @@ definitions: type: object properties: individualId: - $ref: '#/definitions/individualId' +# $ref: '#/definitions/individualId' + type: array + items: + type: string id: $ref: '#/definitions/idForSearch' clientReferenceId: @@ -456,9 +463,12 @@ definitions: gender: $ref: '#/definitions/gender' mobileNumber: - type: string + type: array + items: + type: string + maxLength: 20 description: Mobile number of the user - maxLength: 20 + socialCategory: type: string description: Social category of the user diff --git a/docs/health-api-specs/contracts/registries/product.yml b/docs/health-api-specs/contracts/registries/product.yml index f99aff159ae..7b5c6fe903b 100644 --- a/docs/health-api-specs/contracts/registries/product.yml +++ b/docs/health-api-specs/contracts/registries/product.yml @@ -311,13 +311,19 @@ definitions: description: Define the type of product example: 'DRUG' name: - type: string + type: array + items: + type: string + example: Paracetamol description: Capture name of the product - example: Paracetamol + manufacturer: - type: string + type: array + items: + type: string + example: 'J&J' description: Capture manufacturer of product - example: 'J&J' + ProductVariant: type: object @@ -368,9 +374,11 @@ definitions: id: $ref: '#/definitions/idForSearch' productId: - type: string - minLength: 2 - maxLength: 64 + type: array + items: + type: string + minLength: 2 + maxLength: 64 description: Product for which this variant is being created sku: type: string diff --git a/docs/health-api-specs/contracts/stock.yml b/docs/health-api-specs/contracts/stock.yml index d2df236940d..f3f513188f0 100644 --- a/docs/health-api-specs/contracts/stock.yml +++ b/docs/health-api-specs/contracts/stock.yml @@ -504,6 +504,7 @@ definitions: - LOST_IN_TRANSIT - DAMAGED_IN_STORAGE - DAMAGED_IN_TRANSIT + description: This field accepts values from enum and if an invalid value is provided, it will default to null. wayBillNumber: type: string minLength: 2 @@ -588,7 +589,10 @@ definitions: facilityId: $ref: '#/definitions/facilityId' productVariantId: - $ref: '#/definitions/productVariantId' +# $ref: '#/definitions/productVariantId' + type: array + items: + type: string referenceId: $ref: '#/definitions/referenceId' referenceIdType: @@ -602,8 +606,10 @@ definitions: transactingPartyType: $ref: '#/definitions/transactingPartyType' wayBillNumber: - $ref: '#/definitions/wayBillNumber' - +# $ref: '#/definitions/wayBillNumber' + type: array + items: + type: string StockReconciliation: type: object required: @@ -656,9 +662,16 @@ definitions: clientReferenceId: $ref: '#/definitions/clientReferenceIdForSearch' facilityId: - $ref: '#/definitions/facilityId' +# $ref: '#/definitions/facilityId' + type: array + items: + type: string + example: FacilityA productVariantId: - $ref: '#/definitions/productVariantId' +# $ref: '#/definitions/productVariantId' + type: array + items: + type: string StockRequest: diff --git a/docs/health-api-specs/er/household-registry-er.txt b/docs/health-api-specs/er/household-registry-er.txt new file mode 100644 index 00000000000..77560bd84fe --- /dev/null +++ b/docs/health-api-specs/er/household-registry-er.txt @@ -0,0 +1,63 @@ +Table address { + id varchar [pk] + tenantId varchar + clientReferenceId varchar(64) + doorNo varchar(64) + latitude double + longitude double + locationAccuracy int + type varchar(64) + addressLine1 varchar(256) + addressLine2 varchar(256) + landmark varchar(256) + city varchar(256) + pincode varchar(64) + buildingName varchar(256) + street varchar(256) + // additionalDetails json + localityCode varchar(64) //Reference to master data + wardcode varchar(256) + // createdBy varchar(64) + // createdTime bigint + // lastModifiedBy varchar(64) + // lastModifiedTime bigint + // rowVersion bigint + // isDeleted bool +} + +Table household { + id varchar [pk] + tenantId varchar + clientReferenceId varchar(64) + numberOfMembers int + addressId varchar [ref: > address.id] + additionalDetails json + createdBy varchar(64) + createdTime bigint + lastModifiedBy varchar(64) + lastModifiedTime bigint + rowVersion bigint + isDeleted bool +} + +Table household_member { + id varchar [pk] + tenantId varchar + clientreferenceid varchar(64) + individualId varchar(64) //[ref: > individual.id] + individualClientReferenceId varchar(64) //[ref: > individual.id] + householdId varchar(64) [ref: > household.id] + householdClientReferenceId varchar(64) [ref: > household.clientreferenceid] + isHeadOfHousehold bool + additionalDetails json + createdBy varchar(64) + createdTime bigint + lastModifiedBy varchar(64) + lastModifiedTime bigint + rowVersion bigint + isDeleted bool + clientCreatedBy varchar(64) + clientCreatedTime bigint + clientLastModifiedBy varchar(64) + clientLastModifiedTime bigint +} \ No newline at end of file diff --git a/docs/health-api-specs/er/individual-registry-er.txt b/docs/health-api-specs/er/individual-registry-er.txt new file mode 100644 index 00000000000..3d38143f0ab --- /dev/null +++ b/docs/health-api-specs/er/individual-registry-er.txt @@ -0,0 +1,105 @@ +TABLE individual { + id varchar [pk] + userId varchar(64) + clientReferenceId varchar(64) + tenantId varchar + givenName varchar(200) + familyName varchar(200) + otherNames varchar(200) + dateOfBirth bigint + gender varchar(10) + bloodGroup varchar(10) + mobileNumber varchar(20) + altContactNumber varchar(20) + email varchar(200) + fatherName varchar(100) + husbandName varchar(100) + photo varchar + additionalDetails json + createdBy varchar(64) + createdTime bigint + lastModifiedBy varchar(64) + lastModifiedTime bigint + rowVersion bigint + isDeleted bool + individualid varchar(64) + relationship varchar(100) + issystemuser bool + username varchar(64) + password varchar(200) + type varchar(64) + roles json + useruuid varchar(64) + issystemuseractive bool + clientcreatedtime bigint + clientlastmodifiedtime bigint + clientcreatedby varchar(64) + clientlastmodifiedby varchar(64) + +} +Table individual_identifier { + id varchar [pk] + individualId varchar [ref: > individual.id] + identifierType varchar(64) + identifierId varchar(64) + clientReferenceId varchar(64) + createdBy varchar(64) + createdTime bigint + lastModifiedBy varchar(64) + lastModifiedTime bigint + rowVersion bigint + isDeleted bool +} +Table address { + id varchar [pk] + tenantId varchar + clientReferenceId varchar(64) + doorNo varchar(64) + latitude double + longitude double + locationAccuracy int + type varchar(64) + addressLine1 varchar(256) + addressLine2 varchar(256) + landmark varchar(256) + city varchar(256) + pincode varchar(64) + buildingName varchar(256) + street varchar(256) + // additionalDetails json + localityCode varchar(64) //Reference to master data + wardcode varchar(256) + // createdBy varchar(64) + // createdTime bigint + // lastModifiedBy varchar(64) + // lastModifiedTime bigint + // rowVersion bigint + // isDeleted bool +} + +Table individual_address { + individualId varchar [ref: > individual.id] + addressId varchar [ref: > address.id] + type varchar(64) + createdBy varchar(64) + createdTime bigint + lastModifiedBy varchar(64) + lastModifiedTime bigint + // rowVersion bigint + isDeleted bool +} + +Table individual_skill { + id varchar [pk] + clientReferenceId varchar(64) [unique] + individualId varchar [ref: > individual.id] + type varchar(64) + level varchar(64) + experience varchar(64) + createdBy varchar(64) + createdTime bigint + lastModifiedBy varchar(64) + lastModifiedTime bigint + rowVersion bigint + isDeleted bool +} diff --git a/docs/health-api-specs/er/referral-registry-er.txt b/docs/health-api-specs/er/referral-registry-er.txt new file mode 100644 index 00000000000..874cd99ed4d --- /dev/null +++ b/docs/health-api-specs/er/referral-registry-er.txt @@ -0,0 +1,46 @@ +TABLE referral { + id varchar(64) [primary key] + clientreferenceid varchar(64) + tenantid varchar(1000) + projectbeneficiaryid varchar(64) + projectbeneficiaryclientreferenceid varchar(64) + referrerid varchar(100) + recipientid varchar(100) + recipienttype varchar(100) + reasons jsonb + sideeffectid varchar(100) [ref: > side_effect.id] + sideeffectclientreferenceid varchar(100) [ref: > side_effect.clientreferenceid] + createdby varchar(64) + createdtime bigint + lastmodifiedby varchar(64) + lastmodifiedtime bigint + clientcreatedby varchar(64) + clientcreatedtime bigint + clientlastmodifiedby varchar(64) + clientlastmodifiedtime bigint + rowversion bigint + isdeleted boolean + additionaldetails jsonb +} + +TABLE side_effect { + id varchar(64) [primary key] + clientreferenceid varchar(64) + tenantid varchar(1000) + taskid varchar(64) + taskclientreferenceid varchar(64) + projectbeneficiaryid varchar(64) + projectbeneficiaryclientreferenceid varchar(64) + symptoms jsonb + createdby varchar(64) + createdtime bigint + lastmodifiedby varchar(64) + lastmodifiedtime bigint + clientcreatedby varchar(64) + clientcreatedtime bigint + clientlastmodifiedby varchar(64) + clientlastmodifiedtime bigint + rowversion bigint + isdeleted boolean + additionaldetails jsonb +} diff --git a/docs/health-api-specs/er/stock-registry-er.txt b/docs/health-api-specs/er/stock-registry-er.txt new file mode 100644 index 00000000000..cae4d67e785 --- /dev/null +++ b/docs/health-api-specs/er/stock-registry-er.txt @@ -0,0 +1,52 @@ +Table stock { + id varchar [pk] + clientReferenceId varchar(64) [unique] + tenantId varchar(1000) + facilityId varchar(64) //[ref: > facility.id] + productVariantId varchar(64) //[ref: > product_variant.id] + quantity bigint + referenceId varchar(200) + referenceIdType varchar(100) + transactionType varchar(100) + transactionReason varchar(100) + transactingPartyId varchar(64) + transactingPartyType varchar(100) + additionalDetails json + createdBy varchar(64) + createdTime bigint + lastModifiedBy varchar(64) + lastModifiedTime bigint + rowVersion bigint + isDeleted bool + waybillNUmber varchar(200) + dateofentry bigint + clientcreatedtime bigint + clientlastmodifiedtime bigint + clientcreatedby varchar(64) + clientlastmodifiedby varchar(64) + sendertype varchar(128) + receivertype varchar(128) + senderid varchar(128) + receiverid varchar(128) + +} + +Table stock_reconciliation_log { + id varchar [pk] + clientReferenceId varchar [unique] //store id provided by frontend + tenantId varchar(1000) + productVariantId varchar(64) //[ref: > product_variant.id] + facilityId varchar(64) //[ref: > facility.id] + referenceId varchar(64) + referenceIdType varchar(64) + dateOfReconciliation bigint + calculatedCount int + physicalRecordedCount int + commentsOnReconciliation varchar + createdAt bigint + modifiedAt bigint + createdBy varchar + modifiedBy varchar + additionalFields json + isDeleted bool +} \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_create.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_create.puml new file mode 100644 index 00000000000..031f8b42e19 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_create.puml @@ -0,0 +1,140 @@ +@startuml +title HFReferral - Bulk Create +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant ProjectService as ps +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/hf-referral/v1/bulk/_create +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: HFReferral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +loop for each hfReferral + alt record already exists + alt record found in cache + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 1 row + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note + end + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Check if record already exists + activate db + db -> rm: 1 row + deactivate db + rm -> rc: Put data in cache using clientReferenceId/serverGeneratedId + activate rc + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note + end + alt projectId invalid + rm -> ps: Check if projectId exists + activate ps + ps -> db: Check if projectId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> ps: Check if projectId exists + activate ps + ps -> db: Check if projectId exists + activate db + db -> ps: n row + deactivate db + ps -> rm: n row + deactivate ps + alt projectFacilityId invalid + rm -> ps: Check if projectFacilityId exists + activate ps + ps -> db: Check if projectFacilityId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> ps: Check if projectFacilityId exists + activate ps + ps -> db: Check if projectFacilityId exists + activate db + db -> ps: n row + deactivate db + ps -> rm: n row + deactivate ps + rm -> k: HFReferral Data /persist_topic + activate k + rm -> rc: Put HFReferral Data against clientReferenceId/serverGeneratedId in cache + activate rc + deactivate rc + group async + prs -> k: Consume HFReferral Data + activate prs + idx -> k: Consume HFReferral Data + activate idx + idx -> el: Store HFReferral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist HFReferral Data + activate db + deactivate db + deactivate prs + end + deactivate k +end + +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_delete.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_delete.puml new file mode 100644 index 00000000000..0f8eab2fa9b --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_delete.puml @@ -0,0 +1,153 @@ +@startuml +title HFReferral - Bulk Delete +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant RedisCache as rc +queue Kafka as k +database Database as db +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el + +c -> rm : /referralmanagement/hf-referral/v1/bulk/_delete +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: HFReferral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +loop for each hfReferral + alt id is null + rm -> rm: Check if HFReferral object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note + end + rm -> rm: Check if HFReferral id is not null + alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: HFReferral Data /error_topic + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + s -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note + end + alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc + end + rm -> rc: Fetch the existing record + activate rc + rc -> rm: 1 row + deactivate rc + alt Duplicate Entry is present [Unique entity validation failed] + rm -> rm: Check if HFReferral object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note + end + rm -> rm: Duplicate Entry is not present [Unique entity validation successful] + alt incorrect rowVersion + s -> s: Compare rowVersion between request and db + s -> s: Incorrect rowVersion [request: should be +1 only] + s -> k: HFReferral Data /error_topic + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + s -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: BAD_REQUEST + end note + end + s -> s: Compare rowVersion between request and db + s -> s: rowVersion in request = rowVersion in db + 1 + rm -> k: HFReferral Data /persist_topic + activate k + rm -> rc: Put HFReferral Data against clientReferenceId/serverGeneratedId in cache + activate rc + deactivate rc + group async + prs -> k: Consume HFReferral Data + activate prs + idx -> k: Consume HFReferral Data + activate idx + idx -> el: Store HFReferral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist HFReferral Data + activate db + deactivate db + deactivate prs + end + deactivate k +end +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_update.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_update.puml new file mode 100644 index 00000000000..693993065b6 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_update.puml @@ -0,0 +1,205 @@ +@startuml +title HFReferral - Bulk Update +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant RedisCache as rc +queue Kafka as k +database Database as db +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el + +c -> rm : /referralmanagement/hf-referral/v1/bulk/_update +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: HFReferral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +loop for each hfReferral + alt id is null + rm -> rm: Check if HFReferral object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note + end + rm -> rm: Check if HFReferral id is not null + alt isDeleted is true + rm -> rm: Check if HFReferral object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note + end + rm -> rm: Check if HFReferral object isDeleted is not true + alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: HFReferral Data /error_topic + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note + end + alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: n row + deactivate db + rm -> rc: n record + activate rc + deactivate rc + end + rm -> rc: Fetch the existing record + activate rc + rc -> rm: n row + deactivate rc + alt projectId invalid + rm -> ps: Check if projectId exists + activate ps + ps -> db: Check if projectId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> ps: Check if projectId exists + activate ps + ps -> db: Check if projectId exists + activate db + db -> ps: n row + deactivate db + ps -> rm: n row + deactivate ps + alt projectFacilityId invalid + rm -> ps: Check if projectFacilityId exists + activate ps + ps -> db: Check if projectFacilityId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> ps: Check if projectFacilityId exists + activate ps + ps -> db: Check if projectFacilityId exists + activate db + db -> ps: n row + deactivate db + ps -> rm: n row + deactivate ps + alt Duplicate Entry is present [Unique entity validation failed] + rm -> rm: Check if HFReferral object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note + end + rm -> rm: Duplicate Entry is not present [Unique entity validation successful] + alt incorrect rowVersion + s -> s: Compare rowVersion between request and db + s -> s: Incorrect rowVersion [request: should be +1 only] + s -> k: HFReferral Data /error_topic + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + s -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: BAD_REQUEST + end note + end + s -> s: Compare rowVersion between request and db + s -> s: rowVersion in request = rowVersion in db + 1 + rm -> k: HFReferral Data /persist_topic + activate k + rm -> rc: Put HFReferral Data against clientReferenceId/serverGeneratedId in cache + activate rc + deactivate rc + group async + prs -> k: Consume HFReferral Data + activate prs + idx -> k: Consume HFReferral Data + activate idx + idx -> el: Store HFReferral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist HFReferral Data + activate db + deactivate db + deactivate prs + end + deactivate k +end +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/create.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/create.puml new file mode 100644 index 00000000000..b83117a4e43 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/create.puml @@ -0,0 +1,137 @@ +@startuml +title HFReferral - Create +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant ProjectService as ps +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/hf-referral/v1/_create +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: HFReferral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +alt record already exists + alt record found in cache + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 1 row + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note + end + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Check if record already exists + activate db + db -> rm: 1 row + deactivate db + rm -> rc: Put data in cache using clientReferenceId/serverGeneratedId + activate rc + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note +end +alt projectId invalid + rm -> ps: Check if projectId exists + activate ps + ps -> db: Check if projectId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> ps: Check if projectId exists +activate ps +ps -> db: Check if projectId exists +activate db +db -> ps: 1 row +deactivate db +ps -> rm: 1 row +deactivate ps +alt projectFacilityId invalid + rm -> ps: Check if projectFacilityId exists + activate ps + ps -> db: Check if projectFacilityId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> ps: Check if projectFacilityId exists +activate ps +ps -> db: Check if projectFacilityId exists +activate db +db -> ps: 1 row +deactivate db +ps -> rm: 1 row +deactivate ps +rm -> k: HFReferral Data /persist_topic +activate k +rm -> rc: Put HFReferral Data against clientReferenceId/serverGeneratedId in cache +activate rc +deactivate rc +group async + prs -> k: Consume HFReferral Data + activate prs + idx -> k: Consume HFReferral Data + activate idx + idx -> el: Store HFReferral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist HFReferral Data + activate db + deactivate db + deactivate prs +end +deactivate k +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/delete.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/delete.puml new file mode 100644 index 00000000000..e5d460e53b0 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/delete.puml @@ -0,0 +1,143 @@ +@startuml +title HFReferral - Delete +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant RedisCache as rc +queue Kafka as k +database Database as db +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el + +c -> rm : /referralmanagement/hf-referral/v1/_delete +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: HFReferral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +alt id is null + rm -> rm: Check if HFReferral object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note +end +rm -> rm: Check if HFReferral id is not null +alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: HFReferral Data /error_topic + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + s -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note +end +alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc +end +rm -> rc: Fetch the existing record +activate rc +rc -> rm: 1 row +deactivate rc +alt incorrect rowVersion + s -> s: Compare rowVersion between request and db + s -> s: Incorrect rowVersion [request: should be +1 only] + s -> k: HFReferral Data /error_topic + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + s -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: BAD_REQUEST + end note +end +s -> s: Compare rowVersion between request and db +s -> s: rowVersion in request = rowVersion in db + 1 +rm -> k: HFReferral Data /persist_topic +activate k +rm -> rc: Put HFReferral Data against clientReferenceId/serverGeneratedId in cache +activate rc +deactivate rc +group async + prs -> k: Consume HFReferral Data + activate prs + idx -> k: Consume HFReferral Data + activate idx + idx -> el: Store HFReferral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist HFReferral Data + activate db + deactivate db + deactivate prs +end +deactivate k +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/update.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/update.puml new file mode 100644 index 00000000000..b9db19c7578 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/update.puml @@ -0,0 +1,196 @@ +@startuml +title HFReferral - Update +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant RedisCache as rc +queue Kafka as k +database Database as db +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el + +c -> rm : /referralmanagement/hf-referral/v1/_update +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: HFReferral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +alt id is null + rm -> rm: Check if HFReferral object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note +end +rm -> rm: Check if HFReferral id is not null +alt isDeleted is true + rm -> rm: Check if HFReferral object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note +end +rm -> rm: Check if HFReferral object isDeleted is not true +alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: HFReferral Data /error_topic + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note +end +alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc +end +rm -> rc: Fetch the existing record +activate rc +rc -> rm: 1 row +deactivate rc +alt projectId invalid + rm -> ps: Check if projectId exists + activate ps + ps -> db: Check if projectId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> ps: Check if projectId exists +activate ps +ps -> db: Check if projectId exists +activate db +db -> ps: n row +deactivate db +ps -> rm: n row +deactivate ps +alt projectFacilityId invalid + rm -> ps: Check if projectFacilityId exists + activate ps + ps -> db: Check if projectFacilityId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> ps: Check if projectFacilityId exists +activate ps +ps -> db: Check if projectFacilityId exists +activate db +db -> ps: n row +deactivate db +ps -> rm: n row +deactivate ps +alt incorrect rowVersion + s -> s: Compare rowVersion between request and db + s -> s: Incorrect rowVersion [request: should be +1 only] + s -> k: HFReferral Data /error_topic + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + s -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: BAD_REQUEST + end note +end +s -> s: Compare rowVersion between request and db +s -> s: rowVersion in request = rowVersion in db + 1 +rm -> k: HFReferral Data /persist_topic +activate k +rm -> rc: Put HFReferral Data against clientReferenceId/serverGeneratedId in cache +activate rc +deactivate rc +group async + prs -> k: Consume HFReferral Data + activate prs + idx -> k: Consume HFReferral Data + activate idx + idx -> el: Store HFReferral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist HFReferral Data + activate db + deactivate db + deactivate prs +end +deactivate k + +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_create.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_create.puml new file mode 100644 index 00000000000..ad7d70f7540 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_create.puml @@ -0,0 +1,204 @@ +@startuml +title Referral - Bulk Create +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/v1/bulk/_create +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Referral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +loop for each referral + alt record already exists + alt record found in cache + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 1 row + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note + end + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Check if record already exists + activate db + db -> rm: 1 row + deactivate db + rm -> rc: Put data in cache using clientReferenceId/serverGeneratedId + activate rc + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note + end + alt projectBeneficiaryId invalid + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 1 row + deactivate db + ps -> rm: 1 row + deactivate ps + alt referrerId invalid + rm -> us: Check if referrerId exists + activate us + us -> db: Check if referrerId exists + activate db + db -> us: 0 rows + deactivate db + us -> rm: 0 rows + deactivate us + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> us: Check if referrerId exists + activate us + us -> db: Check if referrerId exists + activate db + db -> us: 1 row + deactivate db + us -> rm: 1 row + deactivate us + alt recipientId invalid + alt recipientType is STAFF + rm -> us: Check if recipientId exists + activate us + us -> db: Check if recipientId exists + activate db + db -> us: 0 rows + deactivate db + us -> rm: 0 rows + deactivate us + end + alt recipientType is FACILITY + rm -> fs: Check if recipientId exists + activate fs + fs -> db: Check if recipientId exists + activate db + db -> fs: 0 rows + deactivate db + fs -> rm: 0 rows + deactivate fs + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + alt recipientType is STAFF + rm -> us: Check if recipientId exists + activate us + us -> db: Check if recipientId exists + activate db + db -> us: 1 row + deactivate db + us -> rm: 1 row + deactivate us + end + alt recipientType is FACILITY + rm -> fs: Check if recipientId exists + activate fs + fs -> db: Check if recipientId exists + activate db + db -> fs: 1 row + deactivate db + fs -> rm: 1 row + deactivate fs + end + alt sideEffectId invalid + rm -> db: Check if sideEffectId exists + activate db + db -> rm: 0 rows + deactivate db + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> db: Check if referrerId exists + activate db + db -> rm: 1 row + deactivate db + + rm -> k: Referral Data /persist_topic + activate k + rm -> rc: Put Referral Data against clientReferenceId/serverGeneratedId in cache + activate rc + deactivate rc + group async + prs -> k: Consume Referral Data + activate prs + idx -> k: Consume Referral Data + activate idx + idx -> el: Store Referral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Referral Data + activate db + deactivate db + deactivate prs + end + deactivate k +end + +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_delete.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_delete.puml new file mode 100644 index 00000000000..38aae93d8b3 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_delete.puml @@ -0,0 +1,133 @@ +@startuml +title Referral - Bulk Delete +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant RedisCache as rc +queue Kafka as k +database Database as db +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el + +c -> rm : /referralmanagement/v1/bulk/_delete +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Referral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +loop for each referral + alt id is null + rm -> rm: Check if Referral object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note + end + rm -> rm: Check if Referral id is not null + alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: Referral Data /error_topic + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + s -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note + end + alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc + end + rm -> rc: Fetch the existing record + activate rc + rc -> rm: 1 row + deactivate rc + alt Duplicate Entry is present [Unique entity validation failed] + rm -> rm: Check if Side Effect object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note + end + rm -> rm: Duplicate Entry is not present [Unique entity validation successful] + rm -> k: Referral Data /persist_topic + activate k + rm -> rc: Put Referral Data against clientReferenceId/serverGeneratedId in cache + activate rc + deactivate rc + group async + prs -> k: Consume Referral Data + activate prs + idx -> k: Consume Referral Data + activate idx + idx -> el: Store Referral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Referral Data + activate db + deactivate db + deactivate prs + end + deactivate k +end +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_update.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_update.puml new file mode 100644 index 00000000000..10d2b662106 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_update.puml @@ -0,0 +1,245 @@ +@startuml +title Referral - Bulk Update +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant RedisCache as rc +queue Kafka as k +database Database as db +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el + +c -> rm : /referralmanagement/v1/bulk/_update +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Referral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +loop for each referral + alt id is null + rm -> rm: Check if Referral object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note + end + rm -> rm: Check if Referral id is not null + alt isDeleted is true + rm -> rm: Check if Referral object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note + end + rm -> rm: Check if Referral object isDeleted is not true + alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: Referral Data /error_topic + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note + end + alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc + end + rm -> rc: Fetch the existing record + activate rc + rc -> rm: 1 row + deactivate rc + alt projectBeneficiaryId invalid + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 1 row + deactivate db + ps -> rm: 1 row + deactivate ps + alt referrerId invalid + rm -> us: Check if referrerId exists + activate us + us -> db: Check if referrerId exists + activate db + db -> us: 0 rows + deactivate db + us -> rm: 0 rows + deactivate us + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> us: Check if referrerId exists + activate us + us -> db: Check if referrerId exists + activate db + db -> us: 1 row + deactivate db + us -> rm: 1 row + deactivate us + alt recipientId invalid + alt recipientType is STAFF + rm -> us: Check if recipientId exists + activate us + us -> db: Check if recipientId exists + activate db + db -> us: 0 rows + deactivate db + us -> rm: 0 rows + deactivate us + end + alt recipientType is FACILITY + rm -> fs: Check if recipientId exists + activate fs + fs -> db: Check if recipientId exists + activate db + db -> fs: 0 rows + deactivate db + fs -> rm: 0 rows + deactivate fs + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + alt recipientType is STAFF + rm -> us: Check if recipientId exists + activate us + us -> db: Check if recipientId exists + activate db + db -> us: 1 row + deactivate db + us -> rm: 1 row + deactivate us + end + alt recipientType is FACILITY + rm -> fs: Check if recipientId exists + activate fs + fs -> db: Check if recipientId exists + activate db + db -> fs: 1 row + deactivate db + fs -> rm: 1 row + deactivate fs + end + alt sideEffectId invalid + rm -> db: Check if sideEffectId exists + activate db + db -> rm: 0 rows + deactivate db + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> db: Check if referrerId exists + activate db + db -> rm: 1 row + deactivate db + alt Duplicate Entry is present [Unique entity validation failed] + rm -> rm: Check if Side Effect object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note + end + rm -> rm: Duplicate Entry is not present [Unique entity validation successful] + rm -> k: Referral Data /persist_topic + activate k + rm -> rc: Put Referral Data against clientReferenceId/serverGeneratedId in cache + activate rc + deactivate rc + group async + prs -> k: Consume Referral Data + activate prs + idx -> k: Consume Referral Data + activate idx + idx -> el: Store Referral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Referral Data + activate db + deactivate db + deactivate prs + end + deactivate k +end +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/create.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/create.puml new file mode 100644 index 00000000000..b3437b4a49c --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/create.puml @@ -0,0 +1,201 @@ +@startuml +title Referral - Create +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/v1/_create +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Referral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +alt record already exists + alt record found in cache + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 1 row + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note + end + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Check if record already exists + activate db + db -> rm: 1 row + deactivate db + rm -> rc: Put data in cache using clientReferenceId/serverGeneratedId + activate rc + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note +end +alt projectBeneficiaryId invalid + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> ps: Check if projectBeneficiaryId exists +activate ps +ps -> db: Check if projectBeneficiaryId exists +activate db +db -> ps: 1 row +deactivate db +ps -> rm: 1 row +deactivate ps +alt referrerId invalid + rm -> us: Check if referrerId exists + activate us + us -> db: Check if referrerId exists + activate db + db -> us: 0 rows + deactivate db + us -> rm: 0 rows + deactivate us + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> us: Check if referrerId exists +activate us +us -> db: Check if referrerId exists +activate db +db -> us: 1 row +deactivate db +us -> rm: 1 row +deactivate us +alt recipientId invalid + alt recipientType is STAFF + rm -> us: Check if recipientId exists + activate us + us -> db: Check if recipientId exists + activate db + db -> us: 0 rows + deactivate db + us -> rm: 0 rows + deactivate us + end + alt recipientType is FACILITY + rm -> fs: Check if recipientId exists + activate fs + fs -> db: Check if recipientId exists + activate db + db -> fs: 0 rows + deactivate db + fs -> rm: 0 rows + deactivate fs + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +alt recipientType is STAFF + rm -> us: Check if recipientId exists + activate us + us -> db: Check if recipientId exists + activate db + db -> us: 1 row + deactivate db + us -> rm: 1 row + deactivate us +end +alt recipientType is FACILITY + rm -> fs: Check if recipientId exists + activate fs + fs -> db: Check if recipientId exists + activate db + db -> fs: 1 row + deactivate db + fs -> rm: 1 row + deactivate fs +end +alt sideEffectId invalid + rm -> db: Check if sideEffectId exists + activate db + db -> rm: 0 rows + deactivate db + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> db: Check if referrerId exists +activate db +db -> rm: 1 row +deactivate db + +rm -> k: Referral Data /persist_topic +activate k +rm -> rc: Put Referral Data against clientReferenceId/serverGeneratedId in cache +activate rc +deactivate rc +group async + prs -> k: Consume Referral Data + activate prs + idx -> k: Consume Referral Data + activate idx + idx -> el: Store Referral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Referral Data + activate db + deactivate db + deactivate prs +end +deactivate k +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/delete.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/delete.puml new file mode 100644 index 00000000000..6e67539432a --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/delete.puml @@ -0,0 +1,124 @@ +@startuml +title Referral - Delete +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant RedisCache as rc +queue Kafka as k +database Database as db +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el + +c -> rm : /referralmanagement/v1/_delete +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Referral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +alt id is null + rm -> rm: Check if Referral object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note +end +rm -> rm: Check if Referral id is not null +alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: Referral Data /error_topic + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + s -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note +end +alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc +end +rm -> rc: Fetch the existing record +activate rc +rc -> rm: 1 row +deactivate rc + +rm -> k: Referral Data /persist_topic +activate k +rm -> rc: Put Referral Data against clientReferenceId/serverGeneratedId in cache +activate rc +deactivate rc +group async + prs -> k: Consume Referral Data + activate prs + idx -> k: Consume Referral Data + activate idx + idx -> el: Store Referral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Referral Data + activate db + deactivate db + deactivate prs +end +deactivate k +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/update.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/update.puml new file mode 100644 index 00000000000..e08b8b98607 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/update.puml @@ -0,0 +1,237 @@ +@startuml +title Referral - Update +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant RedisCache as rc +queue Kafka as k +database Database as db +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el + +c -> rm : /referralmanagement/v1/_update +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Referral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +alt id is null + rm -> rm: Check if Referral object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note +end +rm -> rm: Check if Referral id is not null +alt isDeleted is true + rm -> rm: Check if Referral object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note +end +rm -> rm: Check if Referral object isDeleted is not true +alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: Referral Data /error_topic + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note +end +alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc +end +rm -> rc: Fetch the existing record +activate rc +rc -> rm: 1 row +deactivate rc +alt projectBeneficiaryId invalid + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> ps: Check if projectBeneficiaryId exists +activate ps +ps -> db: Check if projectBeneficiaryId exists +activate db +db -> ps: 1 row +deactivate db +ps -> rm: 1 row +deactivate ps +alt referrerId invalid + rm -> us: Check if referrerId exists + activate us + us -> db: Check if referrerId exists + activate db + db -> us: 0 rows + deactivate db + us -> rm: 0 rows + deactivate us + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> us: Check if referrerId exists +activate us +us -> db: Check if referrerId exists +activate db +db -> us: 1 row +deactivate db +us -> rm: 1 row +deactivate us +alt recipientId invalid + alt recipientType is STAFF + rm -> us: Check if recipientId exists + activate us + us -> db: Check if recipientId exists + activate db + db -> us: 0 rows + deactivate db + us -> rm: 0 rows + deactivate us + end + alt recipientType is FACILITY + rm -> fs: Check if recipientId exists + activate fs + fs -> db: Check if recipientId exists + activate db + db -> fs: 0 rows + deactivate db + fs -> rm: 0 rows + deactivate fs + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +alt recipientType is STAFF + rm -> us: Check if recipientId exists + activate us + us -> db: Check if recipientId exists + activate db + db -> us: 1 row + deactivate db + us -> rm: 1 row + deactivate us +end +alt recipientType is FACILITY + rm -> fs: Check if recipientId exists + activate fs + fs -> db: Check if recipientId exists + activate db + db -> fs: 1 row + deactivate db + fs -> rm: 1 row + deactivate fs +end +alt sideEffectId invalid + rm -> db: Check if sideEffectId exists + activate db + db -> rm: 0 rows + deactivate db + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> db: Check if referrerId exists +activate db +db -> rm: 1 row +deactivate db + +rm -> k: Referral Data /persist_topic +activate k +rm -> rc: Put Referral Data against clientReferenceId/serverGeneratedId in cache +activate rc +deactivate rc +group async + prs -> k: Consume Referral Data + activate prs + idx -> k: Consume Referral Data + activate idx + idx -> el: Store Referral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Referral Data + activate db + deactivate db + deactivate prs +end +deactivate k + +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_create.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_create.puml new file mode 100644 index 00000000000..9808045815c --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_create.puml @@ -0,0 +1,141 @@ +@startuml +title Side Effect - Bulk Create +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/side-effect/v1/bulk/_create +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Side Effect Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +loop for each side-effect + alt record already exists + alt record found in cache + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 1 row + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note + end + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Check if record already exists + activate db + db -> rm: 1 row + deactivate db + rm -> rc: Put data in cache using clientReferenceId/serverGeneratedId + activate rc + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note + end + alt projectTaskId invalid + rm -> ps: Check if projectTaskId exists + activate ps + ps -> db: Check if projectTaskId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: BAD_REQUEST + end note + end + rm -> ps: Check if projectTaskId exists + activate ps + ps -> db: Check if projectTaskId exists + activate db + db -> ps: 1 row + deactivate db + ps -> rm: 1 row + deactivate ps + alt projectBeneficiaryId invalid + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 1 row + deactivate db + ps -> rm: 1 row + deactivate ps + rm -> k: Side Effect Data /persist_topic + activate k + rm -> rc: Put Side Effect Data against clientReferenceId/serverGeneratedId in cache + activate rc + deactivate rc + group async + prs -> k: Consume Side Effect Data + activate prs + idx -> k: Consume Side Effect Data + activate idx + idx -> el: Store Side Effect Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Side Effect Data + activate db + deactivate db + deactivate prs + end + deactivate k +end +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_delete.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_delete.puml new file mode 100644 index 00000000000..1d95721ab4c --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_delete.puml @@ -0,0 +1,125 @@ +@startuml +title Side Effect - Bulk Delete +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/side-effect/v1/bulk/_delete +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Side Effect Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +loop for each side-effect + alt id is null + rm -> rm: Check if Side Effect object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note + end + rm -> rm: Check if Side Effect id is not null + alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: Side Effect Data /error_topic + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note + end + alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc + end + rm -> rc: Fetch the existing record + activate rc + rc -> rm: 1 row + deactivate rc + rm -> k: Side Effect Data /persist_topic + activate k + rm -> rc: Put Side Effect Data against clientReferenceId/serverGeneratedId in cache + activate rc + deactivate rc + group async + prs -> k: Consume Side Effect Data + activate prs + idx -> k: Consume Side Effect Data + activate idx + idx -> el: Store Side Effect Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Side Effect Data + activate db + deactivate db + deactivate prs + end + deactivate k +end + +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_update.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_update.puml new file mode 100644 index 00000000000..85606389c27 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_update.puml @@ -0,0 +1,177 @@ +@startuml +title Side Effect - Bulk Update +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/side-effect/v1/bulk/_update +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Side Effect Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +loop for each side-effect + alt id is null + rm -> rm: Check if Side Effect object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note + end + rm -> rm: Check if Side Effect id is not null + alt isDeleted is true + rm -> rm: Check if Side Effect object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note + end + rm -> rm: Check if Side Effect object isDeleted is not true + alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: Side Effect Data /error_topic + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note + end + alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc + end + rm -> rc: Fetch the existing record + activate rc + rc -> rm: 1 row + deactivate rc + alt projectTaskId invalid + rm -> ps: Check if projectTaskId exists + activate ps + ps -> db: Check if projectTaskId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: BAD_REQUEST + end note + end + rm -> ps: Check if projectTaskId exists + activate ps + ps -> db: Check if projectTaskId exists + activate db + db -> ps: 1 row + deactivate db + ps -> rm: 1 row + deactivate ps + alt projectBeneficiaryId invalid + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 1 row + deactivate db + ps -> rm: 1 row + deactivate ps + rm -> k: Side Effect Data /persist_topic + activate k + rm -> rc: Put Side Effect Data against clientReferenceId/serverGeneratedId in cache + activate rc + deactivate rc + group async + prs -> k: Consume Side Effect Data + activate prs + idx -> k: Consume Side Effect Data + activate idx + idx -> el: Store Side Effect Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Side Effect Data + activate db + deactivate db + deactivate prs + end + deactivate k +end + +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/create.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/create.puml new file mode 100644 index 00000000000..94d0a3b95ca --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/create.puml @@ -0,0 +1,140 @@ +@startuml +title Side Effect - Create +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/side-effect/v1/_create +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Side Effect Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +alt record already exists + alt record found in cache + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 1 row + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note + end + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Check if record already exists + activate db + db -> rm: 1 row + deactivate db + rm -> rc: Put data in cache using clientReferenceId/serverGeneratedId + activate rc + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note +end +alt projectTaskId invalid + rm -> ps: Check if projectTaskId exists + activate ps + ps -> db: Check if projectTaskId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: BAD_REQUEST + end note +end +rm -> ps: Check if projectTaskId exists +activate ps +ps -> db: Check if projectTaskId exists +activate db +db -> ps: 1 row +deactivate db +ps -> rm: 1 row +deactivate ps +alt projectBeneficiaryId invalid + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> ps: Check if projectBeneficiaryId exists +activate ps +ps -> db: Check if projectBeneficiaryId exists +activate db +db -> ps: 1 row +deactivate db +ps -> rm: 1 row +deactivate ps +rm -> k: Side Effect Data /persist_topic +activate k +rm -> rc: Put Side Effect Data against clientReferenceId/serverGeneratedId in cache +activate rc +deactivate rc +group async + prs -> k: Consume Side Effect Data + activate prs + idx -> k: Consume Side Effect Data + activate idx + idx -> el: Store Side Effect Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Side Effect Data + activate db + deactivate db + deactivate prs +end +deactivate k + +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/delete.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/delete.puml new file mode 100644 index 00000000000..77727af23d2 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/delete.puml @@ -0,0 +1,123 @@ +@startuml +title Side Effect - Delete +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/side-effect/v1/_delete +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Side Effect Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +alt id is null + rm -> rm: Check if Side Effect object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note +end +rm -> rm: Check if Side Effect id is not null +alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: Side Effect Data /error_topic + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note +end +alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc +end +rm -> rc: Fetch the existing record +activate rc +rc -> rm: 1 row +deactivate rc +rm -> k: Side Effect Data /persist_topic +activate k +rm -> rc: Put Side Effect Data against clientReferenceId/serverGeneratedId in cache +activate rc +deactivate rc +group async + prs -> k: Consume Side Effect Data + activate prs + idx -> k: Consume Side Effect Data + activate idx + idx -> el: Store Side Effect Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Side Effect Data + activate db + deactivate db + deactivate prs +end +deactivate k + +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/update.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/update.puml new file mode 100644 index 00000000000..896e5d40fbc --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/update.puml @@ -0,0 +1,175 @@ +@startuml +title Side Effect - Update +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/side-effect/v1/_update +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Side Effect Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +alt id is null + rm -> rm: Check if Side Effect object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note +end +rm -> rm: Check if Side Effect id is not null +alt isDeleted is true + rm -> rm: Check if Side Effect object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note +end +rm -> rm: Check if Side Effect object isDeleted is not true +alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: Side Effect Data /error_topic + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note +end +alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc +end +rm -> rc: Fetch the existing record +activate rc +rc -> rm: 1 row +deactivate rc +alt projectTaskId invalid + rm -> ps: Check if projectTaskId exists + activate ps + ps -> db: Check if projectTaskId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: BAD_REQUEST + end note +end +rm -> ps: Check if projectTaskId exists +activate ps +ps -> db: Check if projectTaskId exists +activate db +db -> ps: 1 row +deactivate db +ps -> rm: 1 row +deactivate ps +alt projectBeneficiaryId invalid + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> ps: Check if projectBeneficiaryId exists +activate ps +ps -> db: Check if projectBeneficiaryId exists +activate db +db -> ps: 1 row +deactivate db +ps -> rm: 1 row +deactivate ps +rm -> k: Side Effect Data /persist_topic +activate k +rm -> rc: Put Side Effect Data against clientReferenceId/serverGeneratedId in cache +activate rc +deactivate rc +group async + prs -> k: Consume Side Effect Data + activate prs + idx -> k: Consume Side Effect Data + activate idx + idx -> el: Store Side Effect Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Side Effect Data + activate db + deactivate db + deactivate prs +end +deactivate k + +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/edcr/service/egov/egov-edcr-extract/src/test/resources/Parking-test.dxf~ b/edcr/service/egov/egov-edcr-extract/src/test/resources/Parking-test.dxf~ deleted file mode 100644 index 0075c9c2aeb..00000000000 --- a/edcr/service/egov/egov-edcr-extract/src/test/resources/Parking-test.dxf~ +++ /dev/null @@ -1,113500 +0,0 @@ -999 -dxfrw 0.6.3 - 0 -SECTION - 2 -HEADER - 9 -$ACADVER - 1 -AC1021 - 9 -$DWGCODEPAGE - 3 -ANSI_1252 - 9 -$INSBASE - 10 -0 - 20 -0 - 30 -0 - 9 -$EXTMIN - 10 -10000000000 - 20 -10000000000 - 30 -0 - 9 -$EXTMAX - 10 --10000000000 - 20 --10000000000 - 30 -0 - 9 -$LIMMIN - 10 -0 - 20 -0 - 9 -$LIMMAX - 10 -12 - 20 -9 - 9 -$ORTHOMODE - 70 - 0 - 9 -$REGENMODE - 70 - 1 - 9 -$FILLMODE - 70 - 1 - 9 -$QTEXTMODE - 70 - 0 - 9 -$MIRRTEXT - 70 - 0 - 9 -$LTSCALE - 40 -1 - 9 -$ATTMODE - 70 - 1 - 9 -$TEXTSIZE - 40 -0.2 - 9 -$TRACEWID - 40 -0.05 - 9 -$TEXTSTYLE - 7 -Standard - 9 -$CLAYER - 8 -BLK_1_FLR_0_COVERED_PARKING - 9 -$CELTYPE - 6 -ByLayer - 9 -$CECOLOR - 62 - 1 - 9 -$CELTSCALE - 40 -1 - 9 -$DISPSILH - 70 - 0 - 9 -$DIMSCALE - 40 -1 - 9 -$DIMASZ - 40 -0.18 - 9 -$DIMEXO - 40 -0.0625 - 9 -$DIMDLI - 40 -0.38 - 9 -$DIMRND - 40 -0 - 9 -$DIMDLE - 40 -0 - 9 -$DIMEXE - 40 -0.18 - 9 -$DIMTP - 40 -0 - 9 -$DIMTM - 40 -0 - 9 -$DIMTXT - 40 -0.18 - 9 -$DIMCEN - 40 -0.09 - 9 -$DIMTSZ - 40 -0 - 9 -$DIMTOL - 70 - 0 - 9 -$DIMLIM - 70 - 0 - 9 -$DIMTIH - 70 - 1 - 9 -$DIMTOH - 70 - 1 - 9 -$DIMSE1 - 70 - 0 - 9 -$DIMSE2 - 70 - 0 - 9 -$DIMTAD - 70 - 0 - 9 -$DIMZIN - 70 - 0 - 9 -$DIMBLK - 1 - - 9 -$DIMASO - 70 - 1 - 9 -$DIMSHO - 70 - 1 - 9 -$DIMPOST - 1 - - 9 -$DIMAPOST - 1 - - 9 -$DIMALT - 70 - 0 - 9 -$DIMALTD - 70 - 2 - 9 -$DIMALTF - 40 -25.4 - 9 -$DIMLFAC - 40 -1 - 9 -$DIMTOFL - 70 - 0 - 9 -$DIMTVP - 40 -0 - 9 -$DIMTIX - 70 - 0 - 9 -$DIMSOXD - 70 - 0 - 9 -$DIMSAH - 70 - 0 - 9 -$DIMBLK1 - 1 - - 9 -$DIMBLK2 - 1 - - 9 -$DIMSTYLE - 2 -Standard - 9 -$DIMCLRD - 70 - 0 - 9 -$DIMCLRE - 70 - 0 - 9 -$DIMCLRT - 70 - 0 - 9 -$DIMTFAC - 40 -1 - 9 -$DIMGAP - 40 -0.09 - 9 -$DIMJUST - 70 - 0 - 9 -$DIMSD1 - 70 - 0 - 9 -$DIMSD2 - 70 - 0 - 9 -$DIMTOLJ - 70 - 1 - 9 -$DIMTZIN - 70 - 0 - 9 -$DIMALTZ - 70 - 0 - 9 -$DIMALTTZ - 70 - 0 - 9 -$DIMUPT - 70 - 0 - 9 -$DIMDEC - 70 - 4 - 9 -$DIMTDEC - 70 - 4 - 9 -$DIMALTU - 70 - 2 - 9 -$DIMALTTD - 70 - 2 - 9 -$DIMTXSTY - 7 -Standard - 9 -$DIMAUNIT - 70 - 0 - 9 -$DIMADEC - 70 - 0 - 9 -$DIMALTRND - 40 -0 - 9 -$DIMAZIN - 70 - 0 - 9 -$DIMDSEP - 70 - 46 - 9 -$DIMATFIT - 70 - 3 - 9 -$DIMFRAC - 70 - 0 - 9 -$DIMLDRBLK - 1 - - 9 -$DIMLUNIT - 70 - 2 - 9 -$DIMLWD - 70 - -2 - 9 -$DIMLWE - 70 - -2 - 9 -$DIMTMOVE - 70 - 0 - 9 -$DIMFXL - 40 -40 - 9 -$DIMFXLON - 70 - 1 - 9 -$DIMJOGANG - 40 -0.7853981633974483 - 9 -$DIMTFILL - 70 - 1 - 9 -$DIMTFILLCLR - 70 - 0 - 9 -$DIMARCSYM - 70 - 1 - 9 -$DIMLTYPE - 6 -Continuous - 9 -$DIMLTEX1 - 6 -ByLayer - 9 -$DIMLTEX2 - 6 -ByLayer - 9 -$LUNITS - 70 - 2 - 9 -$LUPREC - 70 - 4 - 9 -$SKETCHINC - 40 -0.1 - 9 -$FILLETRAD - 40 -0 - 9 -$AUNITS - 70 - 0 - 9 -$AUPREC - 70 - 0 - 9 -$MENU - 1 -. - 9 -$ELEVATION - 40 -0 - 9 -$PELEVATION - 40 -0 - 9 -$THICKNESS - 40 -0 - 9 -$LIMCHECK - 70 - 0 - 9 -$CHAMFERA - 40 -0 - 9 -$CHAMFERB - 40 -0 - 9 -$CHAMFERC - 40 -0 - 9 -$CHAMFERD - 40 -0 - 9 -$SKPOLY - 70 - 0 - 9 -$USRTIMER - 70 - 1 - 9 -$ANGBASE - 50 -0 - 9 -$ANGDIR - 70 - 0 - 9 -$PDMODE - 70 - 0 - 9 -$PDSIZE - 40 -0 - 9 -$PLINEWID - 40 -0 - 9 -$SPLFRAME - 70 - 0 - 9 -$SPLINETYPE - 70 - 6 - 9 -$SPLINESEGS - 70 - 8 - 9 -$HANDSEED - 5 -20000 - 9 -$SURFTAB1 - 70 - 6 - 9 -$SURFTAB2 - 70 - 6 - 9 -$SURFTYPE - 70 - 6 - 9 -$SURFU - 70 - 6 - 9 -$SURFV - 70 - 6 - 9 -$UCSBASE - 2 - - 9 -$UCSNAME - 2 - - 9 -$UCSORG - 10 -0 - 20 -0 - 30 -0 - 9 -$UCSXDIR - 10 -1 - 20 -0 - 30 -0 - 9 -$UCSYDIR - 10 -0 - 20 -1 - 30 -0 - 9 -$UCSORTHOREF - 2 - - 9 -$UCSORTHOVIEW - 70 - 0 - 9 -$UCSORGTOP - 10 -0 - 20 -0 - 30 -0 - 9 -$UCSORGBOTTOM - 10 -0 - 20 -0 - 30 -0 - 9 -$UCSORGLEFT - 10 -0 - 20 -0 - 30 -0 - 9 -$UCSORGRIGHT - 10 -0 - 20 -0 - 30 -0 - 9 -$UCSORGFRONT - 10 -0 - 20 -0 - 30 -0 - 9 -$UCSORGBACK - 10 -0 - 20 -0 - 30 -0 - 9 -$PUCSBASE - 2 - - 9 -$PUCSNAME - 2 - - 9 -$PUCSORG - 10 -0 - 20 -0 - 30 -0 - 9 -$PUCSXDIR - 10 -1 - 20 -0 - 30 -0 - 9 -$PUCSYDIR - 10 -0 - 20 -1 - 30 -0 - 9 -$PUCSORTHOREF - 2 - - 9 -$PUCSORTHOVIEW - 70 - 0 - 9 -$PUCSORGTOP - 10 -0 - 20 -0 - 30 -0 - 9 -$PUCSORGBOTTOM - 10 -0 - 20 -0 - 30 -0 - 9 -$PUCSORGLEFT - 10 -0 - 20 -0 - 30 -0 - 9 -$PUCSORGRIGHT - 10 -0 - 20 -0 - 30 -0 - 9 -$PUCSORGFRONT - 10 -0 - 20 -0 - 30 -0 - 9 -$PUCSORGBACK - 10 -0 - 20 -0 - 30 -0 - 9 -$USERI1 - 70 - 0 - 9 -$USERI2 - 70 - 0 - 9 -$USERI3 - 70 - 0 - 9 -$USERI4 - 70 - 0 - 9 -$USERI5 - 70 - 0 - 9 -$USERR1 - 40 -0 - 9 -$USERR2 - 40 -0 - 9 -$USERR3 - 40 -0 - 9 -$USERR4 - 40 -0 - 9 -$USERR5 - 40 -0 - 9 -$WORLDVIEW - 70 - 1 - 9 -$SHADEDGE - 70 - 3 - 9 -$SHADEDIF - 70 - 70 - 9 -$TILEMODE - 70 - 1 - 9 -$MAXACTVP - 70 - 64 - 9 -$PINSBASE - 10 -0 - 20 -0 - 30 -0 - 9 -$PLIMCHECK - 70 - 0 - 9 -$PEXTMIN - 10 -0 - 20 -0 - 30 -0 - 9 -$PEXTMAX - 10 -0 - 20 -0 - 30 -0 - 9 -$GRIDMODE - 70 - 0 - 9 -$SNAPSTYLE - 70 - 0 - 9 -$PLIMMIN - 10 -0 - 20 -0 - 9 -$PLIMMAX - 10 -12 - 20 -9 - 9 -$UNITMODE - 70 - 0 - 9 -$VISRETAIN - 70 - 1 - 9 -$PLINEGEN - 70 - 0 - 9 -$PSLTSCALE - 70 - 1 - 9 -$TREEDEPTH - 70 - 3020 - 9 -$CMLSTYLE - 2 -Standard - 9 -$CMLJUST - 70 - 0 - 9 -$CMLSCALE - 40 -1 - 9 -$PROXYGRAPHICS - 70 - 1 - 9 -$MEASUREMENT - 70 - 0 - 9 -$CELWEIGHT -370 - -1 - 9 -$ENDCAPS -280 - 0 - 9 -$JOINSTYLE -280 - 0 - 9 -$LWDISPLAY -290 - 0 - 9 -$INSUNITS - 70 - 6 - 9 -$HYPERLINKBASE - 1 - - 9 -$STYLESHEET - 1 - - 9 -$XEDIT -290 - 1 - 9 -$CEPSNTYPE -380 - 0 - 9 -$PSTYLEMODE -290 - 1 - 9 -$EXTNAMES -290 - 1 - 9 -$PSVPSCALE - 40 -0 - 9 -$OLESTARTUP -290 - 0 - 9 -$SORTENTS -280 - 127 - 9 -$INDEXCTL -280 - 0 - 9 -$HIDETEXT -280 - 1 - 9 -$XCLIPFRAME -290 - 0 - 9 -$HALOGAP -280 - 0 - 9 -$OBSCOLOR - 70 - 257 - 9 -$OBSLTYPE -280 - 0 - 9 -$INTERSECTIONDISPLAY -280 - 0 - 9 -$INTERSECTIONCOLOR - 70 - 257 - 9 -$DIMASSOC -280 - 2 - 9 -$PROJECTNAME - 1 - - 9 -$CAMERADISPLAY -290 - 0 - 9 -$LENSLENGTH - 40 -50 - 9 -$CAMERAHEIGHT - 40 -0 - 9 -$STEPSPERSEC - 40 -2 - 9 -$STEPSIZE - 40 -6 - 9 -$3DDWFPREC - 40 -2 - 9 -$PSOLWIDTH - 40 -0.25 - 9 -$PSOLHEIGHT - 40 -4 - 9 -$LOFTANG1 - 40 -1.570795999999999 - 9 -$LOFTANG2 - 40 -1.570795999999999 - 9 -$LOFTMAG1 - 40 -0 - 9 -$LOFTMAG2 - 40 -0 - 9 -$LOFTPARAM - 70 - 7 - 9 -$LOFTNORMALS -280 - 1 - 9 -$LATITUDE - 40 -37.795 - 9 -$LONGITUDE - 40 --122.394 - 9 -$NORTHDIRECTION - 40 -0 - 9 -$TIMEZONE - 70 --8000 - 9 -$LIGHTGLYPHDISPLAY -280 - 1 - 9 -$TILEMODELIGHTSYNCH -280 - 1 - 9 -$SOLIDHIST -280 - 0 - 9 -$SHOWHIST -280 - 1 - 9 -$DWFFRAME -280 - 2 - 9 -$DGNFRAME -280 - 0 - 9 -$REALWORLDSCALE -290 - 1 - 9 -$INTERFERECOLOR - 62 - 1 - 9 -$CSHADOW -280 - 0 - 9 -$SHADOWPLANELOCATION - 40 -0 - 0 -ENDSEC - 0 -SECTION - 2 -CLASSES - 0 -ENDSEC - 0 -SECTION - 2 -TABLES - 0 -TABLE - 2 -VPORT - 5 -8 -330 -0 -100 -AcDbSymbolTable - 70 - 1 - 0 -VPORT - 5 -31 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbViewportTableRecord - 2 -*ACTIVE - 70 - 0 - 10 -0 - 20 -0 - 11 -1 - 21 -1 - 12 -1890.972724807764 - 22 -580.6761978901518 - 13 -0 - 23 -0 - 14 -10 - 24 -10 - 15 -10 - 25 -10 - 16 -0 - 26 -0 - 36 -1 - 17 -0 - 27 -0 - 37 -0 - 40 -129.2679479148683 - 41 -1.31858407079646 - 42 -50 - 43 -0 - 44 -0 - 50 -0 - 51 -0 - 71 - 0 - 72 - 100 - 73 - 1 - 74 - 3 - 75 - 0 - 76 - 0 - 77 - 0 - 78 - 0 -281 - 0 - 65 - 1 -110 -0 -120 -0 -130 -0 -111 -1 -121 -0 -131 -0 -112 -0 -122 -1 -132 -0 - 79 - 0 -146 -0 -348 -10020 - 60 - 7 - 61 - 5 -292 -1 -282 - 1 -141 -0 -142 -0 - 63 - 250 -421 -3358443 - 0 -ENDTAB - 0 -TABLE - 2 -LTYPE - 5 -5 -330 -0 -100 -AcDbSymbolTable - 70 - 4 - 0 -LTYPE - 5 -14 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -ByBlock - 70 - 0 - 3 - - 72 - 65 - 73 - 0 - 40 -0 - 0 -LTYPE - 5 -15 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -ByLayer - 70 - 0 - 3 - - 72 - 65 - 73 - 0 - 40 -0 - 0 -LTYPE - 5 -16 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -Continuous - 70 - 0 - 3 -Solid line - 72 - 65 - 73 - 0 - 40 -0 - 0 -LTYPE - 5 -32 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DOT - 70 - 0 - 3 -Dot . . . . . . . . . . . . . . . . . . . . . . - 72 - 65 - 73 - 2 - 40 -6.35 - 49 -0 - 74 - 0 - 49 --6.35 - 74 - 0 - 0 -LTYPE - 5 -33 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DOTTINY - 70 - 0 - 3 -Dot (.15x) ..................................... - 72 - 65 - 73 - 2 - 40 -0.9525 - 49 -0 - 74 - 0 - 49 --0.9525 - 74 - 0 - 0 -LTYPE - 5 -34 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DOT2 - 70 - 0 - 3 -Dot (.5x) ..................................... - 72 - 65 - 73 - 2 - 40 -3.175 - 49 -0 - 74 - 0 - 49 --3.175 - 74 - 0 - 0 -LTYPE - 5 -35 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DOTX2 - 70 - 0 - 3 -Dot (2x) . . . . . . . . . . . . . - 72 - 65 - 73 - 2 - 40 -12.7 - 49 -0 - 74 - 0 - 49 --12.7 - 74 - 0 - 0 -LTYPE - 5 -36 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DASHED - 70 - 0 - 3 -Dashed _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - 72 - 65 - 73 - 2 - 40 -19.05 - 49 -12.7 - 74 - 0 - 49 --6.35 - 74 - 0 - 0 -LTYPE - 5 -37 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DASHEDTINY - 70 - 0 - 3 -Dashed (.15x) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - 72 - 65 - 73 - 2 - 40 -2.8575 - 49 -1.905 - 74 - 0 - 49 --0.9525 - 74 - 0 - 0 -LTYPE - 5 -38 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DASHED2 - 70 - 0 - 3 -Dashed (.5x) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - 72 - 65 - 73 - 2 - 40 -9.524999999999999 - 49 -6.35 - 74 - 0 - 49 --3.175 - 74 - 0 - 0 -LTYPE - 5 -39 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DASHEDX2 - 70 - 0 - 3 -Dashed (2x) ____ ____ ____ ____ ____ ___ - 72 - 65 - 73 - 2 - 40 -38.09999999999999 - 49 -25.4 - 74 - 0 - 49 --12.7 - 74 - 0 - 0 -LTYPE - 5 -3A -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DASHDOT - 70 - 0 - 3 -Dash dot __ . __ . __ . __ . __ . __ . __ . __ - 72 - 65 - 73 - 4 - 40 -25.4 - 49 -12.7 - 74 - 0 - 49 --6.35 - 74 - 0 - 49 -0 - 74 - 0 - 49 --6.35 - 74 - 0 - 0 -LTYPE - 5 -3B -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DASHDOTTINY - 70 - 0 - 3 -Dash dot (.15x) _._._._._._._._._._._._._._._. - 72 - 65 - 73 - 4 - 40 -3.81 - 49 -1.905 - 74 - 0 - 49 --0.9525 - 74 - 0 - 49 -0 - 74 - 0 - 49 --0.9525 - 74 - 0 - 0 -LTYPE - 5 -3C -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DASHDOT2 - 70 - 0 - 3 -Dash dot (.5x) _._._._._._._._._._._._._._._. - 72 - 65 - 73 - 4 - 40 -12.7 - 49 -6.35 - 74 - 0 - 49 --3.175 - 74 - 0 - 49 -0 - 74 - 0 - 49 --3.175 - 74 - 0 - 0 -LTYPE - 5 -3D -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DASHDOTX2 - 70 - 0 - 3 -Dash dot (2x) ____ . ____ . ____ . ___ - 72 - 65 - 73 - 4 - 40 -50.8 - 49 -25.4 - 74 - 0 - 49 --12.7 - 74 - 0 - 49 -0 - 74 - 0 - 49 --12.7 - 74 - 0 - 0 -LTYPE - 5 -3E -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DIVIDE - 70 - 0 - 3 -Divide ____ . . ____ . . ____ . . ____ . . ____ - 72 - 65 - 73 - 6 - 40 -31.75 - 49 -12.7 - 74 - 0 - 49 --6.35 - 74 - 0 - 49 -0 - 74 - 0 - 49 --6.35 - 74 - 0 - 49 -0 - 74 - 0 - 49 --6.35 - 74 - 0 - 0 -LTYPE - 5 -3F -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DIVIDETINY - 70 - 0 - 3 -Divide (.15x) __..__..__..__..__..__..__..__.._ - 72 - 65 - 73 - 6 - 40 -4.7625 - 49 -1.905 - 74 - 0 - 49 --0.9525 - 74 - 0 - 49 -0 - 74 - 0 - 49 --0.9525 - 74 - 0 - 49 -0 - 74 - 0 - 49 --0.9525 - 74 - 0 - 0 -LTYPE - 5 -40 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DIVIDE2 - 70 - 0 - 3 -Divide (.5x) __..__..__..__..__..__..__..__.._ - 72 - 65 - 73 - 6 - 40 -15.875 - 49 -6.35 - 74 - 0 - 49 --3.175 - 74 - 0 - 49 -0 - 74 - 0 - 49 --3.175 - 74 - 0 - 49 -0 - 74 - 0 - 49 --3.175 - 74 - 0 - 0 -LTYPE - 5 -41 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DIVIDEX2 - 70 - 0 - 3 -Divide (2x) ________ . . ________ . . _ - 72 - 65 - 73 - 6 - 40 -63.5 - 49 -25.4 - 74 - 0 - 49 --12.7 - 74 - 0 - 49 -0 - 74 - 0 - 49 --12.7 - 74 - 0 - 49 -0 - 74 - 0 - 49 --12.7 - 74 - 0 - 0 -LTYPE - 5 -42 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -BORDER - 70 - 0 - 3 -Border __ __ . __ __ . __ __ . __ __ . __ __ . - 72 - 65 - 73 - 6 - 40 -44.45 - 49 -12.7 - 74 - 0 - 49 --6.35 - 74 - 0 - 49 -12.7 - 74 - 0 - 49 --6.35 - 74 - 0 - 49 -0 - 74 - 0 - 49 --6.35 - 74 - 0 - 0 -LTYPE - 5 -43 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -BORDERTINY - 70 - 0 - 3 -Border (.15x) __.__.__.__.__.__.__.__.__.__.__. - 72 - 65 - 73 - 6 - 40 -6.6675 - 49 -1.905 - 74 - 0 - 49 --0.9525 - 74 - 0 - 49 -1.905 - 74 - 0 - 49 --0.9525 - 74 - 0 - 49 -0 - 74 - 0 - 49 --0.9525 - 74 - 0 - 0 -LTYPE - 5 -44 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -BORDER2 - 70 - 0 - 3 -Border (.5x) __.__.__.__.__.__.__.__.__.__.__. - 72 - 65 - 73 - 6 - 40 -22.225 - 49 -6.35 - 74 - 0 - 49 --3.175 - 74 - 0 - 49 -6.35 - 74 - 0 - 49 --3.175 - 74 - 0 - 49 -0 - 74 - 0 - 49 --3.175 - 74 - 0 - 0 -LTYPE - 5 -45 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -BORDERX2 - 70 - 0 - 3 -Border (2x) ____ ____ . ____ ____ . ___ - 72 - 65 - 73 - 6 - 40 -88.89999999999999 - 49 -25.4 - 74 - 0 - 49 --12.7 - 74 - 0 - 49 -25.4 - 74 - 0 - 49 --12.7 - 74 - 0 - 49 -0 - 74 - 0 - 49 --12.7 - 74 - 0 - 0 -LTYPE - 5 -46 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -CENTER - 70 - 0 - 3 -Center ____ _ ____ _ ____ _ ____ _ ____ _ ____ - 72 - 65 - 73 - 4 - 40 -50.8 - 49 -31.75 - 74 - 0 - 49 --6.35 - 74 - 0 - 49 -6.35 - 74 - 0 - 49 --6.35 - 74 - 0 - 0 -LTYPE - 5 -47 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -CENTERTINY - 70 - 0 - 3 -Center (.15x) ___ _ ___ _ ___ _ ___ _ ___ _ ___ - 72 - 65 - 73 - 4 - 40 -7.619999999999999 - 49 -4.7625 - 74 - 0 - 49 --0.9525 - 74 - 0 - 49 -0.9525 - 74 - 0 - 49 --0.9525 - 74 - 0 - 0 -LTYPE - 5 -48 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -CENTER2 - 70 - 0 - 3 -Center (.5x) ___ _ ___ _ ___ _ ___ _ ___ _ ___ - 72 - 65 - 73 - 4 - 40 -28.575 - 49 -19.05 - 74 - 0 - 49 --3.175 - 74 - 0 - 49 -3.175 - 74 - 0 - 49 --3.175 - 74 - 0 - 0 -LTYPE - 5 -49 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -CENTERX2 - 70 - 0 - 3 -Center (2x) ________ __ ________ __ _____ - 72 - 65 - 73 - 4 - 40 -101.6 - 49 -63.5 - 74 - 0 - 49 --12.7 - 74 - 0 - 49 -12.7 - 74 - 0 - 49 --12.7 - 74 - 0 - 0 -ENDTAB - 0 -TABLE - 2 -LAYER - 5 -2 -330 -0 -100 -AcDbSymbolTable - 70 - 1 - 0 -LAYER - 5 -10 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -0 - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -370 - -3 -390 -F - 0 -LAYER - 5 -4A -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_BSMNT_FOOT_PRINT - 70 - 0 - 62 - 6 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -4B -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_BSMNT_FRONT_YARD - 70 - 0 - 62 - 2 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -4C -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_BSMNT_REAR_YARD - 70 - 0 - 62 - 11 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -4D -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_BSMNT_SIDE_YARD_1 - 70 - 0 - 62 - 171 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -4E -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_BSMNT_SIDE_YARD_2 - 70 - 0 - 62 - 102 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -4F -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_COVERED_AREA - 70 - 0 - 62 - 140 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -50 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_DA_RAMP_1 - 70 - 0 - 62 - 241 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -51 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_-1_BLT_UP_AREA - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -52 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_-1_BLT_UP_AREA_DEDUCT - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -53 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_-1_EXIT_WIDTH_STAIR - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -54 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_-1_HT_ROOM - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -55 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_-1_LIFT_1 - 70 - 0 - 62 - 30 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -56 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_-1_STAIR_1 - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -57 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -58 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_BLT_UP_AREA - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -59 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_BLT_UP_AREA_DEDUCT - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -5A -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_EXIT_WIDTH_DOOR - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -5B -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -5C -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_FIRESTAIR_1 - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -5D -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -5E -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_HT_ROOM - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -5F -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_SP_WC - 70 - 0 - 62 - 6 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -60 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_STAIR_1 - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -61 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_STAIR_1_FLIGHT - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -62 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_WASH - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -63 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_WATER_CLOSET - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -64 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_BLT_UP_AREA - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -65 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_BLT_UP_AREA_DEDUCT - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -66 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -67 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_FIRESTAIR_1 - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -68 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -69 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_HT_ROOM - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -6A -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_STAIR_1 - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -6B -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_STAIR_1_FLIGHT - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -6C -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_URINAL - 70 - 0 - 62 - 60 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -6D -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_WASH - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -6E -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_WATER_CLOSET - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -6F -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_2_BLT_UP_AREA - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -70 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -71 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_2_FIRESTAIR_1 - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -72 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -73 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_2_HT_ROOM - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -74 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_2_STAIR_1 - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -75 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_2_STAIR_1_FLIGHT - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -76 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_3_BLT_UP_AREA - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -77 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_3_EXIT_WIDTH_DOOR - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -78 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_3_FIRESTAIR_1 - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -79 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_HT_OF_BLDG - 70 - 0 - 62 - 5 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -7A -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_0_BLDG_FOOT_PRINT - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -7B -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_0_FRONT_YARD - 70 - 0 - 62 - 2 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -7C -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_0_REAR_YARD - 70 - 0 - 62 - 11 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -7D -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_0_SIDE_YARD1 - 70 - 0 - 62 - 171 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -7E -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_0_SIDE_YARD2 - 70 - 0 - 62 - 102 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -7F -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_1_BLDG_FOOT_PRINT - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -80 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_1_FRONT_YARD - 70 - 0 - 62 - 2 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -81 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_1_REAR_YARD - 70 - 0 - 62 - 11 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -82 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_1_SIDE_YARD1 - 70 - 0 - 62 - 171 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -83 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_1_SIDE_YARD2 - 70 - 0 - 62 - 102 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -84 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_MAX_HEIGHT_CAL - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -85 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_SHADE_OVERHANG - 70 - 0 - 62 - 6 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -86 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -DA_PARKING - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -87 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -DIST_CL_ROAD - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -88 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -DIST_EXIT - 70 - 0 - 62 - 5 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -89 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -Defpoints - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -8A -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -FURNITURE - 70 - 0 - 62 - 13 - 6 -CONTINUOUS -370 - 13 -390 -F - 0 -LAYER - 5 -8B -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -NOTIFIED_ROAD - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -8C -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_COVERED_PARKING - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -370 - 0 -390 -F - 0 -LAYER - 5 -8D -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -PARKING_SLOT - 70 - 0 - 62 - 30 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -8E -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -PLAN_INFO - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -8F -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -PLOT_BOUNDARY - 70 - 0 - 62 - 70 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -90 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -RWH - 70 - 0 - 62 - 4 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -91 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -SHORTEST_DIST_TO_ROAD - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -92 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -Symbols - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -370 - -3 -390 -F - 0 -LAYER - 5 -93 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -TWO_WHEELER_PARKING - 70 - 0 - 62 - 2 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -94 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -WASTE_DISPOSAL - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -95 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -coloumn - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -370 - -3 -390 -F - 0 -ENDTAB - 0 -TABLE - 2 -STYLE - 5 -3 -330 -0 -100 -AcDbSymbolTable - 70 - 3 - 0 -STYLE - 5 -96 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbTextStyleTableRecord - 2 -standard - 70 - 0 - 40 -0 - 41 -1 - 50 -0 - 71 - 0 - 42 -1 - 3 -standard - 4 - - 0 -STYLE - 5 -97 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbTextStyleTableRecord - 2 -title1 - 70 - 0 - 40 -0 - 41 -1 - 50 -0 - 71 - 0 - 42 -1 - 3 -title1 - 4 - - 0 -STYLE - 5 -98 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbTextStyleTableRecord - 2 -arial - 70 - 0 - 40 -0 - 41 -1 - 50 -0 - 71 - 0 - 42 -1 - 3 -arial - 4 - - 0 -STYLE - 5 -99 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbTextStyleTableRecord - 2 -sree - 70 - 0 - 40 -0 - 41 -1 - 50 -0 - 71 - 0 - 42 -1 - 3 -sree - 4 - - 0 -STYLE - 5 -9A -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbTextStyleTableRecord - 2 -arial smal - 70 - 0 - 40 -0 - 41 -1 - 50 -0 - 71 - 0 - 42 -1 - 3 -arial smal - 4 - - 0 -ENDTAB - 0 -TABLE - 2 -VIEW - 5 -6 -330 -0 -100 -AcDbSymbolTable - 70 - 0 - 0 -ENDTAB - 0 -TABLE - 2 -UCS - 5 -7 -330 -0 -100 -AcDbSymbolTable - 70 - 0 - 0 -ENDTAB - 0 -TABLE - 2 -APPID - 5 -9 -330 -0 -100 -AcDbSymbolTable - 70 - 1 - 0 -APPID - 5 -12 -330 -9 -100 -AcDbSymbolTableRecord -100 -AcDbRegAppTableRecord - 2 -ACAD - 70 - 0 - 0 -APPID - 5 -9B -330 -9 -100 -AcDbSymbolTableRecord -100 -AcDbRegAppTableRecord - 2 -LibreCad - 70 - 0 - 0 -ENDTAB - 0 -TABLE - 2 -DIMSTYLE - 5 -A -330 -0 -100 -AcDbSymbolTable - 70 - 1 -100 -AcDbDimStyleTable - 71 - 1 - 0 -DIMSTYLE -105 -9C -330 -A -100 -AcDbSymbolTableRecord -100 -AcDbDimStyleTableRecord - 2 -Standard - 70 - 0 - 40 -1 - 41 -0.18 - 42 -0.0625 - 43 -0.38 - 44 -0.18 - 45 -0 - 46 -0 - 47 -0 - 48 -0 - 49 -40 -140 -0.18 -141 -0.09 -142 -0 -143 -25.4 -144 -1 -145 -0 -146 -1 -147 -0.09 -148 -0 - 71 - 0 - 72 - 0 - 73 - 1 - 74 - 1 - 75 - 0 - 76 - 0 - 77 - 0 - 78 - 0 - 79 - 0 -170 - 0 -171 - 2 -172 - 0 -173 - 0 -174 - 0 -175 - 0 -176 - 0 -177 - 0 -178 - 0 -179 - 0 -271 - 4 -272 - 4 -273 - 2 -274 - 2 -275 - 0 -276 - 0 -277 - 2 -278 - 46 -279 - 0 -280 - 0 -281 - 0 -282 - 0 -283 - 1 -284 - 0 -285 - 0 -286 - 0 -288 - 0 -289 - 3 -290 - 1 -340 -Standard -341 - -371 - -2 -372 - -2 - 0 -ENDTAB - 0 -TABLE - 2 -BLOCK_RECORD - 5 -1 -330 -0 -100 -AcDbSymbolTable - 70 - 2 - 0 -BLOCK_RECORD - 5 -1F -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*Model_Space - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1E -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*Paper_Space - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -9D -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D46 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -A0 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D79 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -A3 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D53 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -A6 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D83 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -A9 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D67 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -AC -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D69 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -AF -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D72 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -B2 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D24 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -B5 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D10 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -B8 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D75 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -BB -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D34 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -BE -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D28 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -C1 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D23 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -C4 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D31 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -C7 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D43 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -CA -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D82 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -CD -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D66 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -D0 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D44 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -D3 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D54 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -D6 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D64 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -D9 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D59 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -DC -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D70 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -DF -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D1 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -E2 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D35 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -E5 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D86 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -E8 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D88 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -EB -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D61 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -EE -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D19 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -F1 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D65 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -F4 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D89 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -F7 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D12 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -FA -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D63 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -FD -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D50 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -100 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D39 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -103 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D71 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -106 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D80 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -109 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D48 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -10C -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D4 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -10F -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D84 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -112 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D74 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -115 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D13 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -118 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D30 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -11B -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D26 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -11E -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D90 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -121 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D47 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -124 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D8 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -127 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D55 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -12A -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D73 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -12D -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D57 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -130 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D5 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -133 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D52 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -136 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D16 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -139 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D2 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -13C -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D6 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -13F -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D38 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -142 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D87 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -145 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D36 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -148 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D27 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -14B -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D3 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -14E -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D20 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -151 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D7 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -154 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D58 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -157 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D81 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -15A -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D11 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -15D -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D62 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -160 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D42 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -163 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D77 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -166 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D17 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -169 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D18 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -16C -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D56 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -16F -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D22 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -172 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D49 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -175 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D60 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -178 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D33 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -17B -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D29 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -17E -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D21 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -181 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D37 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -184 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D32 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -187 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D78 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -18A -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D25 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -18D -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D14 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -190 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D85 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -193 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D76 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -196 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D15 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -199 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D9 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -19C -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D51 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -19F -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D41 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1A2 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D68 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1A5 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D45 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1A8 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D40 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1AB -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -_ArchTick - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1AE -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -15 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1B1 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -tre - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1B4 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*U4 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1B7 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -WELL10 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1BA -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -Basin 22 - 70 - 0 -280 - 1 -281 - 0 - 0 -ENDTAB - 0 -ENDSEC - 0 -SECTION - 2 -BLOCKS - 0 -BLOCK - 5 -20 -330 -1F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*Model_Space - 70 - 0 - 10 -0 - 20 -0 - 30 -0 - 3 -*Model_Space - 1 - - 0 -ENDBLK - 5 -21 -330 -1F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1C -330 -1B -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*Paper_Space - 70 - 0 - 10 -0 - 20 -0 - 30 -0 - 3 -*Paper_Space - 1 - - 0 -ENDBLK - 5 -1D -330 -1F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -9E -330 -9D -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D46 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D46 - 1 - - 0 -LINE - 5 -1BD -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.738675249547 - 20 -1243.552369962674 - 11 -3353.738675249547 - 21 -1243.132369416201 - 0 -SOLID - 5 -1BE -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3353.738675249547 - 20 -1243.552369962674 - 30 -0 - 11 -3353.768647744907 - 21 -1243.372369962674 - 31 -0 - 12 -3353.708702754187 - 22 -1243.372369962674 - 32 -0 - 13 -3353.708702754187 - 23 -1243.372369962674 - 33 -0 - 0 -SOLID - 5 -1BF -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3353.738675249547 - 20 -1242.352368869728 - 30 -0 - 11 -3353.708702754187 - 21 -1242.532368869728 - 31 -0 - 12 -3353.768647744907 - 22 -1242.532368869728 - 32 -0 - 13 -3353.768647744907 - 23 -1242.532368869728 - 33 -0 - 0 -LINE - 5 -1C0 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.738675249547 - 20 -1242.772369416201 - 11 -3353.738675249547 - 21 -1242.352368869728 - 0 -MTEXT - 5 -1C1 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3353.738675249547 - 20 -1242.952369416201 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -1C2 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.738675249528 - 20 -1243.552369962674 - 11 -3353.918675249547 - 21 -1243.552369962674 - 0 -LINE - 5 -1C3 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.73794189703 - 20 -1242.352368869728 - 11 -3353.918675249547 - 21 -1242.352368869728 - 0 -ENDBLK - 5 -9F -330 -9D -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -A1 -330 -A0 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D79 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D79 - 1 - - 0 -LINE - 5 -1C4 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369135 - 20 -1256.28662018356 - 11 -3427.522237369135 - 21 -1257.906620183549 - 0 -SOLID - 5 -1C5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.522237369135 - 20 -1256.28662018356 - 30 -0 - 11 -3427.492264873775 - 21 -1256.46662018356 - 31 -0 - 12 -3427.552209864495 - 22 -1256.46662018356 - 32 -0 - 13 -3427.552209864495 - 23 -1256.46662018356 - 33 -0 - 0 -SOLID - 5 -1C6 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.522237369135 - 20 -1259.886620183537 - 30 -0 - 11 -3427.552209864495 - 21 -1259.706620183537 - 31 -0 - 12 -3427.492264873775 - 22 -1259.706620183537 - 32 -0 - 13 -3427.492264873775 - 23 -1259.706620183537 - 33 -0 - 0 -LINE - 5 -1C7 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369135 - 20 -1258.266620183549 - 11 -3427.522237369135 - 21 -1259.886620183537 - 0 -MTEXT - 5 -1C8 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3427.394713937268 - 20 -1258.086620183549 - 30 -0 - 40 -0.18 - 41 -0.7000000000000224 - 71 - 5 - 72 - 1 - 1 -3.6000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -1C9 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369135 - 20 -1256.28662018356 - 11 -3427.702237369135 - 21 -1256.28662018356 - 0 -LINE - 5 -1CA -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369135 - 20 -1259.886620183537 - 11 -3427.702237369135 - 21 -1259.886620183537 - 0 -ENDBLK - 5 -A2 -330 -A0 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -A4 -330 -A3 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D53 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D53 - 1 - - 0 -LINE - 5 -1CB -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.137986023692 - 20 -1258.300104171694 - 11 -3316.137986023692 - 21 -1257.480104146831 - 0 -SOLID - 5 -1CC -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3316.137986023692 - 20 -1258.300104171694 - 30 -0 - 11 -3316.167958519052 - 21 -1258.120104171694 - 31 -0 - 12 -3316.108013528332 - 22 -1258.120104171694 - 32 -0 - 13 -3316.108013528332 - 23 -1258.120104171694 - 33 -0 - 0 -SOLID - 5 -1CD -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3316.137986023692 - 20 -1256.300104121969 - 30 -0 - 11 -3316.108013528332 - 21 -1256.480104121969 - 31 -0 - 12 -3316.167958519052 - 22 -1256.480104121969 - 32 -0 - 13 -3316.167958519052 - 23 -1256.480104121969 - 33 -0 - 0 -LINE - 5 -1CE -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.137986023692 - 20 -1257.120104146831 - 11 -3316.137986023692 - 21 -1256.300104121969 - 0 -MTEXT - 5 -1CF -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3316.137986023692 - 20 -1257.300104146831 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -2.0000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -1D0 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.111287422821 - 20 -1258.300104171694 - 11 -3316.317986023692 - 21 -1258.300104171694 - 0 -LINE - 5 -1D1 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.137986023678 - 20 -1256.300104121969 - 11 -3316.317986023692 - 21 -1256.300104121969 - 0 -ENDBLK - 5 -A5 -330 -A3 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -A7 -330 -A6 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D83 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D83 - 1 - - 0 -LINE - 5 -1D2 -100 -AcDbEntity - 8 -BLK_1_FLR_0_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3439.369119896593 - 20 -1252.686620183584 - 11 -3439.369119896593 - 21 -1250.841620183561 - 0 -SOLID - 5 -1D3 -100 -AcDbEntity - 8 -BLK_1_FLR_0_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3439.369119896593 - 20 -1252.686620183584 - 30 -0 - 11 -3439.399092391953 - 21 -1252.506620183584 - 31 -0 - 12 -3439.339147401233 - 22 -1252.506620183584 - 32 -0 - 13 -3439.339147401233 - 23 -1252.506620183584 - 33 -0 - 0 -SOLID - 5 -1D4 -100 -AcDbEntity - 8 -BLK_1_FLR_0_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3439.369119896593 - 20 -1248.636620183537 - 30 -0 - 11 -3439.339147401233 - 21 -1248.816620183537 - 31 -0 - 12 -3439.399092391953 - 22 -1248.816620183537 - 32 -0 - 13 -3439.399092391953 - 23 -1248.816620183537 - 33 -0 - 0 -LINE - 5 -1D5 -100 -AcDbEntity - 8 -BLK_1_FLR_0_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3439.369119896593 - 20 -1250.481620183561 - 11 -3439.369119896593 - 21 -1248.636620183537 - 0 -MTEXT - 5 -1D6 -100 -AcDbEntity - 8 -BLK_1_FLR_0_HT_ROOM - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3439.369119896593 - 20 -1250.661620183561 - 30 -0 - 40 -0.18 - 41 -0.7200000000000111 - 71 - 5 - 72 - 1 - 1 -4.0500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -1D7 -100 -AcDbEntity - 8 -BLK_1_FLR_0_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1252.686620183584 - 11 -3439.549119896593 - 21 -1252.686620183584 - 0 -LINE - 5 -1D8 -100 -AcDbEntity - 8 -BLK_1_FLR_0_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1248.636620183537 - 11 -3439.549119896593 - 21 -1248.636620183537 - 0 -ENDBLK - 5 -A8 -330 -A6 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -AA -330 -A9 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D67 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D67 - 1 - - 0 -LINE - 5 -1D9 -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.727986019337 - 20 -1256.237604148744 - 11 -3316.727986019337 - 21 -1255.983161899994 - 0 -LINE - 5 -1DA -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.477986019337 - 20 -1256.237604148744 - 11 -3317.477986019337 - 21 -1255.983161899994 - 0 -LINE - 5 -1DB -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.727986019337 - 20 -1256.163161899994 - 11 -3317.477986019337 - 21 -1256.163161899994 - 0 -SOLID - 5 -1DC -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3316.727986019337 - 20 -1256.163161899994 - 30 -0 - 11 -3316.907986019337 - 21 -1256.193134395354 - 31 -0 - 12 -3316.907986019337 - 22 -1256.133189404634 - 32 -0 - 13 -3316.907986019337 - 23 -1256.133189404634 - 33 -0 - 0 -SOLID - 5 -1DD -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.477986019337 - 20 -1256.163161899994 - 30 -0 - 11 -3317.297986019337 - 21 -1256.133189404634 - 31 -0 - 12 -3317.297986019337 - 22 -1256.193134395354 - 32 -0 - 13 -3317.297986019337 - 23 -1256.193134395354 - 33 -0 - 0 -MTEXT - 5 -1DE -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3318.121860507742 - 20 -1256.163161899994 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -AB -330 -A9 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -AD -330 -AC -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D69 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D69 - 1 - - 0 -LINE - 5 -1DF -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1256.237604171695 - 11 -3352.938675249461 - 21 -1255.983161922944 - 0 -LINE - 5 -1E0 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.688675249461 - 20 -1256.237604171695 - 11 -3353.688675249461 - 21 -1255.983161922944 - 0 -LINE - 5 -1E1 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1256.163161922944 - 11 -3353.688675249461 - 21 -1256.163161922944 - 0 -SOLID - 5 -1E2 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3352.938675249461 - 20 -1256.163161922944 - 30 -0 - 11 -3353.118675249461 - 21 -1256.193134418304 - 31 -0 - 12 -3353.118675249461 - 22 -1256.133189427584 - 32 -0 - 13 -3353.118675249461 - 23 -1256.133189427584 - 33 -0 - 0 -SOLID - 5 -1E3 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3353.688675249461 - 20 -1256.163161922944 - 30 -0 - 11 -3353.508675249461 - 21 -1256.133189427584 - 31 -0 - 12 -3353.508675249461 - 22 -1256.193134418304 - 32 -0 - 13 -3353.508675249461 - 23 -1256.193134418304 - 33 -0 - 0 -MTEXT - 5 -1E4 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3354.332549737865 - 20 -1256.163161922944 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -AE -330 -AC -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -B0 -330 -AF -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D72 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D72 - 1 - - 0 -LINE - 5 -1E5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3441.644366980692 - 20 -1245.868946037968 - 11 -3440.694366980712 - 21 -1245.868946037968 - 0 -SOLID - 5 -1E6 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3441.284366980692 - 20 -1245.868946037968 - 30 -0 - 11 -3441.464366980692 - 21 -1245.898918533328 - 31 -0 - 12 -3441.464366980692 - 22 -1245.838973542608 - 32 -0 - 13 -3441.464366980692 - 23 -1245.838973542608 - 33 -0 - 0 -SOLID - 5 -1E7 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3441.054366980712 - 20 -1245.868946037968 - 30 -0 - 11 -3440.874366980712 - 21 -1245.838973542608 - 31 -0 - 12 -3440.874366980712 - 22 -1245.898918533328 - 32 -0 - 13 -3440.874366980712 - 23 -1245.898918533328 - 33 -0 - 0 -MTEXT - 5 -1E8 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3441.258357607955 - 20 -1245.996469469835 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.2300 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -1E9 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3441.284366980692 - 20 -1246.12440066169 - 11 -3441.284366980692 - 21 -1245.688946037968 - 0 -LINE - 5 -1EA -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3441.054366980712 - 20 -1246.12440066169 - 11 -3441.054366980712 - 21 -1245.688946037968 - 0 -ENDBLK - 5 -B1 -330 -AF -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -B3 -330 -B2 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D24 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D24 - 1 - - 0 -LINE - 5 -1EB -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3284.525130626578 - 20 -1245.052369962679 - 11 -3284.525130626578 - 21 -1244.482369962678 - 0 -SOLID - 5 -1EC -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3284.525130626578 - 20 -1245.052369962679 - 30 -0 - 11 -3284.555103121938 - 21 -1244.872369962679 - 31 -0 - 12 -3284.495158131218 - 22 -1244.872369962679 - 32 -0 - 13 -3284.495158131218 - 23 -1244.872369962679 - 33 -0 - 0 -SOLID - 5 -1ED -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3284.525130626578 - 20 -1243.552369962679 - 30 -0 - 11 -3284.495158131218 - 21 -1243.732369962679 - 31 -0 - 12 -3284.555103121938 - 22 -1243.732369962679 - 32 -0 - 13 -3284.555103121938 - 23 -1243.732369962679 - 33 -0 - 0 -LINE - 5 -1EE -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3284.525130626578 - 20 -1244.122369962678 - 11 -3284.525130626578 - 21 -1243.552369962679 - 0 -MTEXT - 5 -1EF -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3284.525130626578 - 20 -1244.302369962678 - 30 -0 - 40 -0.18 - 41 -0.6600000000000112 - 71 - 5 - 72 - 1 - 1 -1.5000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -1F0 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3284.699090456707 - 20 -1245.052369962679 - 11 -3284.345130626578 - 21 -1245.052369962679 - 0 -LINE - 5 -1F1 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3284.699090456707 - 20 -1243.552369962679 - 11 -3284.345130626578 - 21 -1243.552369962679 - 0 -ENDBLK - 5 -B4 -330 -B2 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -B6 -330 -B5 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D10 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D10 - 1 - - 0 -LINE - 5 -1F2 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3711.213270720591 - 20 -1109.577723062505 - 11 -3713.636973271638 - 21 -1109.602458632589 - 0 -LINE - 5 -1F3 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3710.973449366783 - 20 -1133.076499321015 - 11 -3713.397151917829 - 21 -1133.101234891099 - 0 -LINE - 5 -1F4 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3713.456982644965 - 20 -1109.60062170307 - 11 -3713.338895711574 - 21 -1121.17131122986 - 0 -SOLID - 5 -1F5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3713.456982644965 - 20 -1109.60062170307 - 30 -0 - 11 -3713.425174780876 - 21 -1109.780306455512 - 31 -0 - 12 -3713.485116650017 - 22 -1109.780918203973 - 32 -0 - 13 -3713.485116650017 - 23 -1109.780918203973 - 33 -0 - 0 -SOLID - 5 -1F6 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3713.217161291157 - 20 -1133.099397961581 - 30 -0 - 11 -3713.248969155246 - 21 -1132.919713209139 - 31 -0 - 12 -3713.189027286105 - 22 -1132.919101460678 - 32 -0 - 13 -3713.189027286105 - 23 -1132.919101460678 - 33 -0 - 0 -LINE - 5 -1F7 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3713.335221661214 - 20 -1121.53131122986 - 11 -3713.217161291157 - 21 -1133.099397961581 - 0 -MTEXT - 5 -1F8 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3713.464588759269 - 20 -1121.35131122986 - 30 -0 - 40 -0.18 - 41 -0.8400000000000225 - 71 - 5 - 72 - 1 - 1 -23.5000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -B7 -330 -B5 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -B9 -330 -B8 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D75 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D75 - 1 - - 0 -LINE - 5 -1F9 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3429.485147392643 - 20 -1247.812661133244 - 11 -3429.984339434687 - 21 -1247.812661133244 - 0 -LINE - 5 -1FA -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3429.984339434687 - 20 -1247.812661133244 - 11 -3429.984339434687 - 21 -1249.558370642658 - 0 -SOLID - 5 -1FB -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbTrace - 10 -3429.485147392643 - 20 -1247.812661133244 - 30 -0 - 11 -3429.665147392643 - 21 -1247.842633628604 - 31 -0 - 12 -3429.665147392643 - 22 -1247.782688637884 - 32 -0 - 13 -3429.665147392643 - 23 -1247.782688637884 - 33 -0 - 0 -ENDBLK - 5 -BA -330 -B8 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -BC -330 -BB -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D34 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D34 - 1 - - 0 -LINE - 5 -1FC -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.674476717278 - 20 -1243.552369962674 - 11 -3300.674476717278 - 21 -1243.132369416201 - 0 -SOLID - 5 -1FD -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.674476717278 - 20 -1243.552369962674 - 30 -0 - 11 -3300.704449212638 - 21 -1243.372369962674 - 31 -0 - 12 -3300.644504221918 - 22 -1243.372369962674 - 32 -0 - 13 -3300.644504221918 - 23 -1243.372369962674 - 33 -0 - 0 -SOLID - 5 -1FE -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.674476717278 - 20 -1242.352368869728 - 30 -0 - 11 -3300.644504221918 - 21 -1242.532368869728 - 31 -0 - 12 -3300.704449212638 - 22 -1242.532368869728 - 32 -0 - 13 -3300.704449212638 - 23 -1242.532368869728 - 33 -0 - 0 -LINE - 5 -1FF -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.674476717278 - 20 -1242.772369416201 - 11 -3300.674476717278 - 21 -1242.352368869728 - 0 -MTEXT - 5 -200 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3300.674476717278 - 20 -1242.952369416201 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -201 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.674476717258 - 20 -1243.552369962674 - 11 -3300.854476717278 - 21 -1243.552369962674 - 0 -LINE - 5 -202 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.673743364761 - 20 -1242.352368869728 - 11 -3300.854476717278 - 21 -1242.352368869728 - 0 -ENDBLK - 5 -BD -330 -BB -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -BF -330 -BE -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D28 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D28 - 1 - - 0 -LINE - 5 -203 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.253068378211 - 20 -1243.552369962679 - 11 -3283.253068378211 - 21 -1243.132369416206 - 0 -SOLID - 5 -204 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3283.253068378211 - 20 -1243.552369962679 - 30 -0 - 11 -3283.283040873571 - 21 -1243.372369962679 - 31 -0 - 12 -3283.223095882851 - 22 -1243.372369962679 - 32 -0 - 13 -3283.223095882851 - 23 -1243.372369962679 - 33 -0 - 0 -SOLID - 5 -205 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3283.253068378211 - 20 -1242.352368869733 - 30 -0 - 11 -3283.223095882851 - 21 -1242.532368869733 - 31 -0 - 12 -3283.283040873571 - 22 -1242.532368869733 - 32 -0 - 13 -3283.283040873571 - 23 -1242.532368869733 - 33 -0 - 0 -LINE - 5 -206 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.253068378211 - 20 -1242.772369416206 - 11 -3283.253068378211 - 21 -1242.352368869733 - 0 -MTEXT - 5 -207 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3283.253068378211 - 20 -1242.952369416206 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -208 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.253068378196 - 20 -1243.552369962679 - 11 -3283.433068378211 - 21 -1243.552369962679 - 0 -LINE - 5 -209 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.252335025697 - 20 -1242.352368869733 - 11 -3283.433068378211 - 21 -1242.352368869733 - 0 -ENDBLK - 5 -C0 -330 -BE -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -C2 -330 -C1 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D23 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D23 - 1 - - 0 -LINE - 5 -20A -100 -AcDbEntity - 8 -DIST_CL_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3702.902121539239 - 20 -1113.765732253328 - 11 -3703.831981610121 - 21 -1108.205644738318 - 0 -SOLID - 5 -20B -100 -AcDbEntity - 8 -DIST_CL_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3702.902121539239 - 20 -1113.765732253328 - 30 -0 - 11 -3702.961374051272 - 21 -1113.5931417255 - 31 -0 - 12 -3702.902250167273 - 22 -1113.583253942471 - 32 -0 - 13 -3702.902250167273 - 23 -1113.583253942471 - 33 -0 - 0 -SOLID - 5 -20C -100 -AcDbEntity - 8 -DIST_CL_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3704.822047500537 - 20 -1102.28555722331 - 30 -0 - 11 -3704.762794988505 - 21 -1102.458147751137 - 31 -0 - 12 -3704.821918872503 - 22 -1102.468035534166 - 32 -0 - 13 -3704.821918872503 - 23 -1102.468035534166 - 33 -0 - 0 -LINE - 5 -20D -100 -AcDbEntity - 8 -DIST_CL_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3703.892187429655 - 20 -1107.845644738318 - 11 -3704.822047500537 - 21 -1102.28555722331 - 0 -MTEXT - 5 -20E -100 -AcDbEntity - 8 -DIST_CL_ROAD - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3703.862084519889 - 20 -1108.025644738318 - 30 -0 - 40 -0.18 - 41 -0.7600000000000335 - 71 - 5 - 72 - 1 - 1 -11.6396 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -20F -100 -AcDbEntity - 8 -DIST_CL_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3702.961422993541 - 20 -1113.775649732927 - 11 -3702.724587119897 - 21 -1113.736041683294 - 0 -LINE - 5 -210 -100 -AcDbEntity - 8 -DIST_CL_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3704.82204750054 - 20 -1102.28555722331 - 11 -3704.644513081195 - 21 -1102.255866653276 - 0 -ENDBLK - 5 -C3 -330 -C1 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -C5 -330 -C4 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D31 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D31 - 1 - - 0 -LINE - 5 -211 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3301.124476731815 - 20 -1243.079906270047 - 11 -3300.224476731909 - 21 -1243.079906270047 - 0 -SOLID - 5 -212 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3301.124476731815 - 20 -1243.079906270047 - 30 -0 - 11 -3300.944476731815 - 21 -1243.049933774687 - 31 -0 - 12 -3300.944476731815 - 22 -1243.109878765407 - 32 -0 - 13 -3300.944476731815 - 23 -1243.109878765407 - 33 -0 - 0 -SOLID - 5 -213 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.224476731909 - 20 -1243.079906270047 - 30 -0 - 11 -3300.404476731909 - 21 -1243.109878765407 - 31 -0 - 12 -3300.404476731909 - 22 -1243.049933774687 - 32 -0 - 13 -3300.404476731909 - 23 -1243.049933774687 - 33 -0 - 0 -MTEXT - 5 -214 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3299.581154767381 - 20 -1243.079906270047 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -0.9000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -215 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3301.124476731815 - 20 -1243.157187090806 - 11 -3301.124476731815 - 21 -1242.899906270047 - 0 -LINE - 5 -216 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.224476731909 - 20 -1243.157187090806 - 11 -3300.224476731909 - 21 -1242.899906270047 - 0 -ENDBLK - 5 -C6 -330 -C4 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -C8 -330 -C7 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D43 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D43 - 1 - - 0 -LINE - 5 -217 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3354.188675264084 - 20 -1243.079906270047 - 11 -3353.288675264177 - 21 -1243.079906270047 - 0 -SOLID - 5 -218 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3354.188675264084 - 20 -1243.079906270047 - 30 -0 - 11 -3354.008675264084 - 21 -1243.049933774687 - 31 -0 - 12 -3354.008675264084 - 22 -1243.109878765407 - 32 -0 - 13 -3354.008675264084 - 23 -1243.109878765407 - 33 -0 - 0 -SOLID - 5 -219 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3353.288675264177 - 20 -1243.079906270047 - 30 -0 - 11 -3353.468675264177 - 21 -1243.109878765407 - 31 -0 - 12 -3353.468675264177 - 22 -1243.049933774687 - 32 -0 - 13 -3353.468675264177 - 23 -1243.049933774687 - 33 -0 - 0 -MTEXT - 5 -21A -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3352.645353299648 - 20 -1243.079906270047 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -0.9000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -21B -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3354.188675264084 - 20 -1243.157187090806 - 11 -3354.188675264084 - 21 -1242.899906270047 - 0 -LINE - 5 -21C -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.288675264177 - 20 -1243.157187090806 - 11 -3353.288675264177 - 21 -1242.899906270047 - 0 -ENDBLK - 5 -C9 -330 -C7 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -CB -330 -CA -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D82 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D82 - 1 - - 0 -LINE - 5 -21D -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3430.011031889974 - 20 -1246.989735042321 - 11 -3430.011031889974 - 21 -1246.49081901033 - 0 -SOLID - 5 -21E -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3430.011031889974 - 20 -1246.989735042321 - 30 -0 - 11 -3430.041004385334 - 21 -1246.809735042321 - 31 -0 - 12 -3429.981059394614 - 22 -1246.809735042321 - 32 -0 - 13 -3429.981059394614 - 23 -1246.809735042321 - 33 -0 - 0 -SOLID - 5 -21F -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3430.011031889974 - 20 -1245.631902978342 - 30 -0 - 11 -3429.981059394614 - 21 -1245.811902978342 - 31 -0 - 12 -3430.041004385334 - 22 -1245.811902978342 - 32 -0 - 13 -3430.041004385334 - 23 -1245.811902978342 - 33 -0 - 0 -LINE - 5 -220 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3430.011031889974 - 20 -1246.13081901033 - 11 -3430.011031889974 - 21 -1245.631902978342 - 0 -MTEXT - 5 -221 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3429.883508458106 - 20 -1246.31081901033 - 30 -0 - 40 -0.18 - 41 -0.6600000000000223 - 71 - 5 - 72 - 1 - 1 -1.3578 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -222 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3429.485147392643 - 20 -1246.989735042321 - 11 -3430.191031889974 - 21 -1246.989735042321 - 0 -LINE - 5 -223 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3429.485147392643 - 20 -1245.631902978342 - 11 -3430.191031889974 - 21 -1245.631902978342 - 0 -ENDBLK - 5 -CC -330 -CA -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -CE -330 -CD -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D66 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D66 - 1 - - 0 -LINE - 5 -224 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1245.414869962667 - 11 -3301.124476717087 - 21 -1246.400390913326 - 0 -LINE - 5 -225 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3302.324476717273 - 20 -1245.414869962667 - 11 -3302.324476717273 - 21 -1246.400390913326 - 0 -LINE - 5 -226 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1246.220390913326 - 11 -3301.30447671718 - 21 -1246.220390913326 - 0 -SOLID - 5 -227 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3301.124476717087 - 20 -1246.220390913326 - 30 -0 - 11 -3301.304476717087 - 21 -1246.250363408686 - 31 -0 - 12 -3301.304476717087 - 22 -1246.190418417966 - 32 -0 - 13 -3301.304476717087 - 23 -1246.190418417966 - 33 -0 - 0 -SOLID - 5 -228 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3302.324476717273 - 20 -1246.220390913326 - 30 -0 - 11 -3302.144476717273 - 21 -1246.190418417966 - 31 -0 - 12 -3302.144476717273 - 22 -1246.250363408686 - 32 -0 - 13 -3302.144476717273 - 23 -1246.250363408686 - 33 -0 - 0 -LINE - 5 -229 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3302.14447671718 - 20 -1246.220390913326 - 11 -3302.324476717273 - 21 -1246.220390913326 - 0 -MTEXT - 5 -22A -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3301.72447671718 - 20 -1246.220390913326 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -CF -330 -CD -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -D1 -330 -D0 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D44 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D44 - 1 - - 0 -LINE - 5 -22B -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.874667968283 - 20 -1243.552369962674 - 11 -3352.874667968284 - 21 -1245.022369962683 - 0 -SOLID - 5 -22C -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3352.874667968283 - 20 -1243.552369962674 - 30 -0 - 11 -3352.844695472923 - 21 -1243.732369962674 - 31 -0 - 12 -3352.904640463643 - 22 -1243.732369962674 - 32 -0 - 13 -3352.904640463643 - 23 -1243.732369962674 - 33 -0 - 0 -SOLID - 5 -22D -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3352.874667968283 - 20 -1246.852369962691 - 30 -0 - 11 -3352.904640463643 - 21 -1246.672369962691 - 31 -0 - 12 -3352.844695472923 - 22 -1246.672369962691 - 32 -0 - 13 -3352.844695472923 - 23 -1246.672369962691 - 33 -0 - 0 -LINE - 5 -22E -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.874667968284 - 20 -1245.382369962683 - 11 -3352.874667968283 - 21 -1246.852369962691 - 0 -MTEXT - 5 -22F -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3352.874667968283 - 20 -1245.202369962683 - 30 -0 - 40 -0.18 - 41 -0.7000000000000224 - 71 - 5 - 72 - 1 - 1 -3.3000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -230 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.874667968265 - 20 -1243.552369962674 - 11 -3352.694667968283 - 21 -1243.552369962674 - 0 -LINE - 5 -231 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.874667968265 - 20 -1246.852369962691 - 11 -3352.694667968283 - 21 -1246.852369962691 - 0 -ENDBLK - 5 -D2 -330 -D0 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -D4 -330 -D3 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D54 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D54 - 1 - - 0 -LINE - 5 -232 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.727986021899 - 20 -1258.430923504448 - 11 -3317.477986023528 - 21 -1258.430923504448 - 0 -SOLID - 5 -233 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3316.727986021899 - 20 -1258.430923504448 - 30 -0 - 11 -3316.907986021899 - 21 -1258.460895999808 - 31 -0 - 12 -3316.907986021899 - 22 -1258.400951009088 - 32 -0 - 13 -3316.907986021899 - 23 -1258.400951009088 - 33 -0 - 0 -SOLID - 5 -234 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.477986023528 - 20 -1258.430923504448 - 30 -0 - 11 -3317.297986023528 - 21 -1258.400951009088 - 31 -0 - 12 -3317.297986023528 - 22 -1258.460895999808 - 32 -0 - 13 -3317.297986023528 - 23 -1258.460895999808 - 33 -0 - 0 -MTEXT - 5 -235 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3318.121307988058 - 20 -1258.430923504448 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -236 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.727986021899 - 20 -1258.300104171694 - 11 -3316.727986021899 - 21 -1258.610923504448 - 0 -LINE - 5 -237 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.477986023528 - 20 -1258.300104171694 - 11 -3317.477986023528 - 21 -1258.610923504448 - 0 -ENDBLK - 5 -D5 -330 -D3 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -D7 -330 -D6 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D64 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D64 - 1 - - 0 -LINE - 5 -238 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1256.237604148744 - 11 -3299.874476717086 - 21 -1255.983161899994 - 0 -LINE - 5 -239 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.624476717086 - 20 -1256.237604148744 - 11 -3300.624476717086 - 21 -1255.983161899994 - 0 -LINE - 5 -23A -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1256.163161899994 - 11 -3300.624476717086 - 21 -1256.163161899994 - 0 -SOLID - 5 -23B -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.874476717086 - 20 -1256.163161899994 - 30 -0 - 11 -3300.054476717086 - 21 -1256.193134395354 - 31 -0 - 12 -3300.054476717086 - 22 -1256.133189404634 - 32 -0 - 13 -3300.054476717086 - 23 -1256.133189404634 - 33 -0 - 0 -SOLID - 5 -23C -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.624476717086 - 20 -1256.163161899994 - 30 -0 - 11 -3300.444476717086 - 21 -1256.133189404634 - 31 -0 - 12 -3300.444476717086 - 22 -1256.193134395354 - 32 -0 - 13 -3300.444476717086 - 23 -1256.193134395354 - 33 -0 - 0 -MTEXT - 5 -23D -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3301.268351205492 - 20 -1256.163161899994 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -D8 -330 -D6 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -DA -330 -D9 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D59 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D59 - 1 - - 0 -LINE - 5 -23E -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.774476718857 - 20 -1258.458460622718 - 11 -3299.02447671866 - 21 -1258.458460622718 - 0 -SOLID - 5 -23F -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.774476718857 - 20 -1258.458460622718 - 30 -0 - 11 -3299.594476718857 - 21 -1258.428488127358 - 31 -0 - 12 -3299.594476718857 - 22 -1258.488433118078 - 32 -0 - 13 -3299.594476718857 - 23 -1258.488433118078 - 33 -0 - 0 -SOLID - 5 -240 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.02447671866 - 20 -1258.458460622718 - 30 -0 - 11 -3299.20447671866 - 21 -1258.488433118078 - 31 -0 - 12 -3299.20447671866 - 22 -1258.428488127358 - 32 -0 - 13 -3299.20447671866 - 23 -1258.428488127358 - 33 -0 - 0 -MTEXT - 5 -241 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3298.381154754131 - 20 -1258.458460622718 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -242 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.774476718857 - 20 -1258.300104121969 - 11 -3299.774476718857 - 21 -1258.638460622718 - 0 -LINE - 5 -243 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.02447671866 - 20 -1258.300104121969 - 11 -3299.02447671866 - 21 -1258.638460622718 - 0 -ENDBLK - 5 -DB -330 -D9 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -DD -330 -DC -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D70 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D70 - 1 - - 0 -LINE - 5 -244 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1245.414869985618 - 11 -3354.188675249461 - 21 -1246.400390936277 - 0 -LINE - 5 -245 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3355.388675249648 - 20 -1245.414869985618 - 11 -3355.388675249648 - 21 -1246.400390936277 - 0 -LINE - 5 -246 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1246.220390936277 - 11 -3354.368675249555 - 21 -1246.220390936277 - 0 -SOLID - 5 -247 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3354.188675249461 - 20 -1246.220390936277 - 30 -0 - 11 -3354.368675249461 - 21 -1246.250363431637 - 31 -0 - 12 -3354.368675249461 - 22 -1246.190418440917 - 32 -0 - 13 -3354.368675249461 - 23 -1246.190418440917 - 33 -0 - 0 -SOLID - 5 -248 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3355.388675249648 - 20 -1246.220390936277 - 30 -0 - 11 -3355.208675249648 - 21 -1246.190418440917 - 31 -0 - 12 -3355.208675249648 - 22 -1246.250363431637 - 32 -0 - 13 -3355.208675249648 - 23 -1246.250363431637 - 33 -0 - 0 -LINE - 5 -249 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3355.208675249555 - 20 -1246.220390936277 - 11 -3355.388675249648 - 21 -1246.220390936277 - 0 -MTEXT - 5 -24A -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3354.788675249555 - 20 -1246.220390936277 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -DE -330 -DC -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -E0 -330 -DF -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D1 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D1 - 1 - - 0 -LINE - 5 -24B -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3282.57882252615 - 20 -1242.352369962667 - 11 -3282.57882252615 - 21 -1241.332201593672 - 0 -LINE - 5 -24C -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3282.57882252615 - 20 -1241.332201593672 - 11 -3282.957429503091 - 21 -1241.332201593672 - 0 -SOLID - 5 -24D -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbTrace - 10 -3282.57882252615 - 20 -1242.352369962667 - 30 -0 - 11 -3282.60879502151 - 21 -1242.172369962667 - 31 -0 - 12 -3282.54885003079 - 22 -1242.172369962667 - 32 -0 - 13 -3282.54885003079 - 23 -1242.172369962667 - 33 -0 - 0 -ENDBLK - 5 -E1 -330 -DF -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -E3 -330 -E2 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D35 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D35 - 1 - - 0 -LINE - 5 -24E -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.024476717244 - 20 -1243.756682050019 - 11 -3299.204476717274 - 21 -1243.756682050019 - 0 -SOLID - 5 -24F -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.024476717244 - 20 -1243.756682050019 - 30 -0 - 11 -3299.204476717244 - 21 -1243.786654545379 - 31 -0 - 12 -3299.204476717244 - 22 -1243.726709554659 - 32 -0 - 13 -3299.204476717244 - 23 -1243.726709554659 - 33 -0 - 0 -SOLID - 5 -250 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.224476717306 - 20 -1243.756682050019 - 30 -0 - 11 -3300.044476717306 - 21 -1243.726709554659 - 31 -0 - 12 -3300.044476717306 - 22 -1243.786654545379 - 32 -0 - 13 -3300.044476717306 - 23 -1243.786654545379 - 33 -0 - 0 -LINE - 5 -251 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.044476717275 - 20 -1243.756682050019 - 11 -3300.224476717306 - 21 -1243.756682050019 - 0 -MTEXT - 5 -252 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3299.624476717275 - 20 -1243.756682050019 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -253 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.024476717244 - 20 -1245.952369962641 - 11 -3299.024476717244 - 21 -1243.576682050019 - 0 -LINE - 5 -254 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.224476717306 - 20 -1243.552370652369 - 11 -3300.224476717306 - 21 -1243.936682050019 - 0 -ENDBLK - 5 -E4 -330 -E2 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -E6 -330 -E5 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D86 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D86 - 1 - - 0 -LINE - 5 -255 -100 -AcDbEntity - 8 -BLK_1_HT_OF_BLDG - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3451.236564734482 - 20 -1259.886620183537 - 11 -3451.236564734482 - 21 -1253.616620184108 - 0 -SOLID - 5 -256 -100 -AcDbEntity - 8 -BLK_1_HT_OF_BLDG - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3451.236564734482 - 20 -1259.886620183537 - 30 -0 - 11 -3451.266537229842 - 21 -1259.706620183537 - 31 -0 - 12 -3451.206592239122 - 22 -1259.706620183537 - 32 -0 - 13 -3451.206592239122 - 23 -1259.706620183537 - 33 -0 - 0 -SOLID - 5 -257 -100 -AcDbEntity - 8 -BLK_1_HT_OF_BLDG - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3451.236564734482 - 20 -1246.986620184678 - 30 -0 - 11 -3451.206592239122 - 21 -1247.166620184678 - 31 -0 - 12 -3451.266537229842 - 22 -1247.166620184678 - 32 -0 - 13 -3451.266537229842 - 23 -1247.166620184678 - 33 -0 - 0 -LINE - 5 -258 -100 -AcDbEntity - 8 -BLK_1_HT_OF_BLDG - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3451.236564734482 - 20 -1253.256620184108 - 11 -3451.236564734482 - 21 -1246.986620184678 - 0 -MTEXT - 5 -259 -100 -AcDbEntity - 8 -BLK_1_HT_OF_BLDG - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3451.236564734482 - 20 -1253.436620184108 - 30 -0 - 40 -0.18 - 41 -0.8 - 71 - 5 - 72 - 1 - 1 -12.9000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -25A -100 -AcDbEntity - 8 -BLK_1_HT_OF_BLDG - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3448.489835352904 - 20 -1259.886620183537 - 11 -3451.416564734482 - 21 -1259.886620183537 - 0 -LINE - 5 -25B -100 -AcDbEntity - 8 -BLK_1_HT_OF_BLDG - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3453.888227601801 - 20 -1246.986620184678 - 11 -3451.056564734482 - 21 -1246.986620184678 - 0 -ENDBLK - 5 -E7 -330 -E5 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -E9 -330 -E8 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D88 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D88 - 1 - - 0 -LINE - 5 -25C -100 -AcDbEntity - 8 -BLK_1_FLR_-1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3439.277894900691 - 20 -1245.78662018356 - 11 -3439.395394900698 - 21 -1245.78662018356 - 0 -LINE - 5 -25D -100 -AcDbEntity - 8 -BLK_1_FLR_-1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3439.277894900691 - 20 -1248.23662018351 - 11 -3439.395394900698 - 21 -1248.23662018351 - 0 -LINE - 5 -25E -100 -AcDbEntity - 8 -BLK_1_FLR_-1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3439.215394900698 - 20 -1245.78662018356 - 11 -3439.215394900698 - 21 -1246.831620183534 - 0 -SOLID - 5 -25F -100 -AcDbEntity - 8 -BLK_1_FLR_-1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3439.215394900698 - 20 -1245.78662018356 - 30 -0 - 11 -3439.185422405338 - 21 -1245.96662018356 - 31 -0 - 12 -3439.245367396058 - 22 -1245.96662018356 - 32 -0 - 13 -3439.245367396058 - 23 -1245.96662018356 - 33 -0 - 0 -SOLID - 5 -260 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3439.215394900698 - 20 -1248.23662018351 - 30 -0 - 11 -3439.245367396058 - 21 -1248.05662018351 - 31 -0 - 12 -3439.185422405338 - 22 -1248.05662018351 - 32 -0 - 13 -3439.185422405338 - 23 -1248.05662018351 - 33 -0 - 0 -LINE - 5 -261 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3439.215394900698 - 20 -1247.191620183534 - 11 -3439.215394900698 - 21 -1248.23662018351 - 0 -MTEXT - 5 -262 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_HT_ROOM - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3439.215394900697 - 20 -1247.011620183534 - 30 -0 - 40 -0.18 - 41 -0.7200000000000111 - 71 - 5 - 72 - 1 - 1 -2.4500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -EA -330 -E8 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -EC -330 -EB -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D61 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D61 - 1 - - 0 -LINE - 5 -263 -100 -AcDbEntity - 8 -DA_PARKING - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3702.98678187502 - 20 -1113.718525507621 - 11 -3703.232053030336 - 21 -1113.166019878484 - 0 -LINE - 5 -264 -100 -AcDbEntity - 8 -DA_PARKING - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3705.84649103904 - 20 -1114.988022384279 - 11 -3706.091762194356 - 21 -1114.435516755143 - 0 -LINE - 5 -265 -100 -AcDbEntity - 8 -DA_PARKING - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3703.159019451676 - 20 -1113.330537647701 - 11 -3704.183400291301 - 21 -1113.78528608603 - 0 -SOLID - 5 -266 -100 -AcDbEntity - 8 -DA_PARKING - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3703.159019451676 - 20 -1113.330537647701 - 30 -0 - 11 -3703.311376117573 - 21 -1113.430965715663 - 31 -0 - 12 -3703.335698324212 - 22 -1113.376176737059 - 32 -0 - 13 -3703.335698324212 - 23 -1113.376176737059 - 33 -0 - 0 -SOLID - 5 -267 -100 -AcDbEntity - 8 -DA_PARKING - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3706.018728615696 - 20 -1114.60003452436 - 30 -0 - 11 -3705.866371949798 - 21 -1114.499606456397 - 31 -0 - 12 -3705.842049743159 - 22 -1114.554395435002 - 32 -0 - 13 -3705.842049743159 - 23 -1114.554395435002 - 33 -0 - 0 -LINE - 5 -268 -100 -AcDbEntity - 8 -DA_PARKING - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3704.99434777607 - 20 -1114.14528608603 - 11 -3706.018728615696 - 21 -1114.60003452436 - 0 -MTEXT - 5 -269 -100 -AcDbEntity - 8 -DA_PARKING - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3704.588874033686 - 20 -1113.96528608603 - 30 -0 - 40 -0.18 - 41 -0.6600000000000112 - 71 - 5 - 72 - 1 - 1 -3.1288 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -ED -330 -EB -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -EF -330 -EE -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D19 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D19 - 1 - - 0 -LINE - 5 -26A -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3724.301952987811 - 20 -1119.259218588684 - 11 -3724.845406284076 - 21 -1116.009645903309 - 0 -SOLID - 5 -26B -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3724.301952987811 - 20 -1119.259218588684 - 30 -0 - 11 -3724.361205499843 - 21 -1119.086628060856 - 31 -0 - 12 -3724.302081615844 - 22 -1119.076740277828 - 32 -0 - 13 -3724.302081615844 - 23 -1119.076740277828 - 33 -0 - 0 -SOLID - 5 -26C -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3725.456101013639 - 20 -1112.358003846994 - 30 -0 - 11 -3725.396848501607 - 21 -1112.530594374822 - 31 -0 - 12 -3725.455972385605 - 22 -1112.54048215785 - 32 -0 - 13 -3725.455972385605 - 23 -1112.54048215785 - 33 -0 - 0 -LINE - 5 -26D -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3724.90561210361 - 20 -1115.649645903309 - 11 -3725.456101013639 - 21 -1112.358003846994 - 0 -MTEXT - 5 -26E -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3725.004803658664 - 20 -1115.829645903309 - 30 -0 - 40 -0.18 - 41 -0.6600000000000112 - 71 - 5 - 72 - 1 - 1 -6.9971 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -26F -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3724.30195298597 - 20 -1119.259218588376 - 11 -3724.124418568469 - 21 -1119.229528018651 - 0 -LINE - 5 -270 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3725.466256737647 - 20 -1112.359702273902 - 11 -3725.278566594297 - 21 -1112.328313276961 - 0 -ENDBLK - 5 -F0 -330 -EE -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -F2 -330 -F1 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D65 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D65 - 1 - - 0 -LINE - 5 -271 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3304.02812267073 - 20 -1243.701237554058 - 11 -3304.02812267073 - 21 -1243.853737554059 - 0 -LINE - 5 -272 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3307.031947087351 - 20 -1243.701237554058 - 11 -3307.031947087351 - 21 -1243.853737554059 - 0 -LINE - 5 -273 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3304.02812267073 - 20 -1243.673737554059 - 11 -3305.090034879041 - 21 -1243.673737554059 - 0 -SOLID - 5 -274 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3304.02812267073 - 20 -1243.673737554059 - 30 -0 - 11 -3304.20812267073 - 21 -1243.703710049419 - 31 -0 - 12 -3304.20812267073 - 22 -1243.643765058699 - 32 -0 - 13 -3304.20812267073 - 23 -1243.643765058699 - 33 -0 - 0 -SOLID - 5 -275 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3307.031947087351 - 20 -1243.673737554059 - 30 -0 - 11 -3306.851947087351 - 21 -1243.643765058699 - 31 -0 - 12 -3306.851947087351 - 22 -1243.703710049419 - 32 -0 - 13 -3306.851947087351 - 23 -1243.703710049419 - 33 -0 - 0 -LINE - 5 -276 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3305.970034879041 - 20 -1243.673737554059 - 11 -3307.031947087351 - 21 -1243.673737554059 - 0 -MTEXT - 5 -277 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_DOOR - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3305.530034879041 - 20 -1243.673737554059 - 30 -0 - 40 -0.18 - 41 -0.7000000000000224 - 71 - 5 - 72 - 1 - 1 -3.0038 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -F3 -330 -F1 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -F5 -330 -F4 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D89 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D89 - 1 - - 0 -LINE - 5 -278 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3663.24658949637 - 20 -1160.007065680477 - 11 -3662.397645356614 - 21 -1160.006700188826 - 0 -LINE - 5 -279 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3663.2576970396 - 20 -1134.207068071412 - 11 -3662.408752899844 - 21 -1134.206702579761 - 0 -LINE - 5 -27A -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3662.577645339932 - 20 -1160.006777683313 - 11 -3662.583121593416 - 21 -1147.286833780797 - 0 -SOLID - 5 -27B -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3662.577645339932 - 20 -1160.006777683313 - 30 -0 - 11 -3662.607695327002 - 21 -1159.826790603901 - 31 -0 - 12 -3662.547750341838 - 22 -1159.826764796088 - 32 -0 - 13 -3662.547750341838 - 23 -1159.826764796088 - 33 -0 - 0 -SOLID - 5 -27C -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3662.588752883162 - 20 -1134.206780074248 - 30 -0 - 11 -3662.558702896093 - 21 -1134.38676715366 - 31 -0 - 12 -3662.618647881256 - 22 -1134.386792961473 - 32 -0 - 13 -3662.618647881256 - 23 -1134.386792961473 - 33 -0 - 0 -LINE - 5 -27D -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3662.583276582406 - 20 -1146.926833780797 - 11 -3662.588752883162 - 21 -1134.206780074248 - 0 -MTEXT - 5 -27E -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3662.710722531596 - 20 -1147.106833780797 - 30 -0 - 40 -0.18 - 41 -0.8400000000000114 - 71 - 5 - 72 - 1 - 1 -25.8000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -F6 -330 -F4 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -F8 -330 -F7 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D12 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D12 - 1 - - 0 -LINE - 5 -27F -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3701.424551457872 - 20 -1133.220728919789 - 11 -3701.542051457873 - 21 -1133.220728919789 - 0 -LINE - 5 -280 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3698.108545772997 - 20 -1107.029812435309 - 11 -3698.226045772998 - 21 -1107.029812435309 - 0 -LINE - 5 -281 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3701.362051457873 - 20 -1133.220728919789 - 11 -3699.728866225455 - 21 -1120.321288420921 - 0 -SOLID - 5 -282 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3701.362051457873 - 20 -1133.220728919789 - 30 -0 - 11 -3701.369177446491 - 21 -1133.03838975569 - 31 -0 - 12 -3701.309707209915 - 22 -1133.045919222736 - 32 -0 - 13 -3701.309707209915 - 23 -1133.045919222736 - 33 -0 - 0 -SOLID - 5 -283 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3698.046045772998 - 20 -1107.029812435309 - 30 -0 - 11 -3698.03891978438 - 21 -1107.212151599408 - 31 -0 - 12 -3698.098390020955 - 22 -1107.204622132362 - 32 -0 - 13 -3698.098390020955 - 23 -1107.204622132362 - 33 -0 - 0 -LINE - 5 -284 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3699.683286986284 - 20 -1119.961288420921 - 11 -3698.046045772998 - 21 -1107.029812435309 - 0 -MTEXT - 5 -285 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3699.577535147486 - 20 -1120.141288420921 - 30 -0 - 40 -0.18 - 41 -0.8600000000000113 - 71 - 5 - 72 - 1 - 1 -26.4000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -F9 -330 -F7 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -FB -330 -FA -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D63 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D63 - 1 - - 0 -LINE - 5 -286 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.703350468274 - 20 -1245.114869326077 - 11 -3283.706205478426 - 21 -1245.747420061637 - 0 -LINE - 5 -287 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3284.903326022838 - 20 -1245.109453250817 - 11 -3284.906181032989 - 21 -1245.742003986377 - 0 -LINE - 5 -288 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.705393058862 - 20 -1245.567421895051 - 11 -3283.885380836144 - 21 -1245.566609522379 - 0 -SOLID - 5 -289 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3283.705393058862 - 20 -1245.567421895051 - 30 -0 - 11 -3283.885526504568 - 21 -1245.596581665558 - 31 -0 - 12 -3283.885255946328 - 22 -1245.536637285416 - 32 -0 - 13 -3283.885255946328 - 23 -1245.536637285416 - 33 -0 - 0 -SOLID - 5 -28A -100 -AcDbEntity - 8 -BLK_1_FLR_-1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3284.905368613425 - 20 -1245.562005819791 - 30 -0 - 11 -3284.725235167718 - 21 -1245.532846049284 - 31 -0 - 12 -3284.725505725959 - 22 -1245.592790429426 - 32 -0 - 13 -3284.725505725959 - 23 -1245.592790429426 - 33 -0 - 0 -LINE - 5 -28B -100 -AcDbEntity - 8 -BLK_1_FLR_-1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3284.725380836144 - 20 -1245.562818192463 - 11 -3284.905368613425 - 21 -1245.562005819791 - 0 -MTEXT - 5 -28C -100 -AcDbEntity - 8 -BLK_1_FLR_-1_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3284.305380836144 - 20 -1245.564713857421 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -FC -330 -FA -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -FE -330 -FD -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D50 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D50 - 1 - - 0 -LINE - 5 -28D -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1258.430923504448 - 11 -3353.688675251091 - 21 -1258.430923504448 - 0 -SOLID - 5 -28E -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3352.938675249461 - 20 -1258.430923504448 - 30 -0 - 11 -3353.118675249461 - 21 -1258.460895999808 - 31 -0 - 12 -3353.118675249461 - 22 -1258.400951009088 - 32 -0 - 13 -3353.118675249461 - 23 -1258.400951009088 - 33 -0 - 0 -SOLID - 5 -28F -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3353.688675251091 - 20 -1258.430923504448 - 30 -0 - 11 -3353.508675251091 - 21 -1258.400951009088 - 31 -0 - 12 -3353.508675251091 - 22 -1258.460895999808 - 32 -0 - 13 -3353.508675251091 - 23 -1258.460895999808 - 33 -0 - 0 -MTEXT - 5 -290 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3354.33199721562 - 20 -1258.430923504448 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -291 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1258.300104171694 - 11 -3352.938675249461 - 21 -1258.610923504448 - 0 -LINE - 5 -292 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.688675251091 - 20 -1258.300104171694 - 11 -3353.688675251091 - 21 -1258.610923504448 - 0 -ENDBLK - 5 -FF -330 -FD -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -101 -330 -100 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D39 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D39 - 1 - - 0 -LINE - 5 -293 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1245.809053745033 - 11 -3318.157986022108 - 21 -1245.809053745033 - 0 -SOLID - 5 -294 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.977986022132 - 20 -1245.809053745033 - 30 -0 - 11 -3318.157986022132 - 21 -1245.839026240393 - 31 -0 - 12 -3318.157986022132 - 22 -1245.779081249673 - 32 -0 - 13 -3318.157986022132 - 23 -1245.779081249673 - 33 -0 - 0 -SOLID - 5 -295 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3319.177986022085 - 20 -1245.809053745033 - 30 -0 - 11 -3318.997986022085 - 21 -1245.779081249673 - 31 -0 - 12 -3318.997986022085 - 22 -1245.839026240393 - 32 -0 - 13 -3318.997986022085 - 23 -1245.839026240393 - 33 -0 - 0 -LINE - 5 -296 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3318.997986022108 - 20 -1245.809053745033 - 11 -3319.177986022085 - 21 -1245.809053745033 - 0 -MTEXT - 5 -297 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3318.577986022108 - 20 -1245.809053745033 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -298 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1245.652369962656 - 11 -3317.977986022132 - 21 -1245.989053745033 - 0 -LINE - 5 -299 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3319.177986022085 - 20 -1245.652369962656 - 11 -3319.177986022085 - 21 -1245.989053745033 - 0 -ENDBLK - 5 -102 -330 -100 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -104 -330 -103 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D71 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D71 - 1 - - 0 -LINE - 5 -29A -100 -AcDbEntity - 8 -BLK_1_FLR_3_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3372.972164166813 - 20 -1255.730104163693 - 11 -3373.152164166811 - 21 -1255.730104163693 - 0 -SOLID - 5 -29B -100 -AcDbEntity - 8 -BLK_1_FLR_3_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3372.972164166813 - 20 -1255.730104163693 - 30 -0 - 11 -3373.152164166813 - 21 -1255.760076659053 - 31 -0 - 12 -3373.152164166813 - 22 -1255.700131668333 - 32 -0 - 13 -3373.152164166813 - 23 -1255.700131668333 - 33 -0 - 0 -SOLID - 5 -29C -100 -AcDbEntity - 8 -BLK_1_FLR_3_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3374.172164166812 - 20 -1255.730104163693 - 30 -0 - 11 -3373.992164166812 - 21 -1255.700131668333 - 31 -0 - 12 -3373.992164166812 - 22 -1255.760076659053 - 32 -0 - 13 -3373.992164166812 - 23 -1255.760076659053 - 33 -0 - 0 -LINE - 5 -29D -100 -AcDbEntity - 8 -BLK_1_FLR_3_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3373.992164166812 - 20 -1255.730104163693 - 11 -3374.172164166812 - 21 -1255.730104163693 - 0 -MTEXT - 5 -29E -100 -AcDbEntity - 8 -BLK_1_FLR_3_EXIT_WIDTH_DOOR - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3373.572164166812 - 20 -1255.730104163693 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -29F -100 -AcDbEntity - 8 -BLK_1_FLR_3_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3372.972164166813 - 20 -1255.550104162563 - 11 -3372.972164166813 - 21 -1255.910104163693 - 0 -LINE - 5 -2A0 -100 -AcDbEntity - 8 -BLK_1_FLR_3_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3374.172164166812 - 20 -1255.730104162563 - 11 -3374.172164166812 - 21 -1255.910104163693 - 0 -ENDBLK - 5 -105 -330 -103 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -107 -330 -106 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D80 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D80 - 1 - - 0 -LINE - 5 -2A1 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369113 - 20 -1246.986620183514 - 11 -3427.522237369113 - 21 -1246.566620183537 - 0 -SOLID - 5 -2A2 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.522237369113 - 20 -1246.986620183514 - 30 -0 - 11 -3427.552209864473 - 21 -1246.806620183514 - 31 -0 - 12 -3427.492264873753 - 22 -1246.806620183514 - 32 -0 - 13 -3427.492264873753 - 23 -1246.806620183514 - 33 -0 - 0 -SOLID - 5 -2A3 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.522237369113 - 20 -1245.78662018356 - 30 -0 - 11 -3427.492264873753 - 21 -1245.96662018356 - 31 -0 - 12 -3427.552209864473 - 22 -1245.96662018356 - 32 -0 - 13 -3427.552209864473 - 23 -1245.96662018356 - 33 -0 - 0 -LINE - 5 -2A4 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369113 - 20 -1246.206620183537 - 11 -3427.522237369113 - 21 -1245.78662018356 - 0 -MTEXT - 5 -2A5 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3427.394713937245 - 20 -1246.386620183537 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2A6 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.76242944449 - 20 -1246.986620183514 - 11 -3427.342237369113 - 21 -1246.986620183514 - 0 -LINE - 5 -2A7 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.671571185602 - 20 -1245.78662018356 - 11 -3427.342237369113 - 21 -1245.78662018356 - 0 -ENDBLK - 5 -108 -330 -106 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -10A -330 -109 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D48 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D48 - 1 - - 0 -LINE - 5 -2A8 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.434456956947 - 20 -1258.300104171694 - 11 -3353.434456956947 - 21 -1257.480104146831 - 0 -SOLID - 5 -2A9 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3353.434456956947 - 20 -1258.300104171694 - 30 -0 - 11 -3353.464429452307 - 21 -1258.120104171694 - 31 -0 - 12 -3353.404484461587 - 22 -1258.120104171694 - 32 -0 - 13 -3353.404484461587 - 23 -1258.120104171694 - 33 -0 - 0 -SOLID - 5 -2AA -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3353.434456956947 - 20 -1256.300104121969 - 30 -0 - 11 -3353.404484461587 - 21 -1256.480104121969 - 31 -0 - 12 -3353.464429452307 - 22 -1256.480104121969 - 32 -0 - 13 -3353.464429452307 - 23 -1256.480104121969 - 33 -0 - 0 -LINE - 5 -2AB -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.434456956947 - 20 -1257.120104146831 - 11 -3353.434456956947 - 21 -1256.300104121969 - 0 -MTEXT - 5 -2AC -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3353.434456956946 - 20 -1257.300104146831 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -2.0000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2AD -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.313675250895 - 20 -1258.300104171694 - 11 -3353.614456956947 - 21 -1258.300104171694 - 0 -LINE - 5 -2AE -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.313675250895 - 20 -1256.300104121969 - 11 -3353.614456956947 - 21 -1256.300104121969 - 0 -ENDBLK - 5 -10B -330 -109 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -10D -330 -10C -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D4 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D4 - 1 - - 0 -LINE - 5 -2AF -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3281.373068378307 - 20 -1257.052749413065 - 11 -3286.751803563298 - 21 -1257.052749413065 - 0 -SOLID - 5 -2B0 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3281.373068378307 - 20 -1257.052749413065 - 30 -0 - 11 -3281.553068378307 - 21 -1257.082721908425 - 31 -0 - 12 -3281.553068378307 - 22 -1257.022776917705 - 32 -0 - 13 -3281.553068378307 - 23 -1257.022776917705 - 33 -0 - 0 -SOLID - 5 -2B1 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3293.070538748289 - 20 -1257.052749413065 - 30 -0 - 11 -3292.890538748289 - 21 -1257.022776917705 - 31 -0 - 12 -3292.890538748289 - 22 -1257.082721908425 - 32 -0 - 13 -3292.890538748289 - 23 -1257.082721908425 - 33 -0 - 0 -LINE - 5 -2B2 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3287.691803563298 - 20 -1257.052749413065 - 11 -3293.070538748289 - 21 -1257.052749413065 - 0 -MTEXT - 5 -2B3 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3287.221803563298 - 20 -1257.180272844932 - 30 -0 - 40 -0.18 - 41 -0.7600000000000224 - 71 - 5 - 72 - 1 - 1 -11.6975 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2B4 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3281.373068378307 - 20 -1258.780104148725 - 11 -3281.373068378307 - 21 -1256.872749413065 - 0 -LINE - 5 -2B5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3293.070538748289 - 20 -1259.050104148744 - 11 -3293.070538748289 - 21 -1256.872749413065 - 0 -ENDBLK - 5 -10E -330 -10C -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -110 -330 -10F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D84 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D84 - 1 - - 0 -LINE - 5 -2B6 -100 -AcDbEntity - 8 -BLK_1_FLR_1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3439.379987518114 - 20 -1252.686620183584 - 11 -3439.379987518114 - 21 -1254.306620183572 - 0 -SOLID - 5 -2B7 -100 -AcDbEntity - 8 -BLK_1_FLR_1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3439.379987518114 - 20 -1252.686620183584 - 30 -0 - 11 -3439.350015022754 - 21 -1252.866620183584 - 31 -0 - 12 -3439.409960013474 - 22 -1252.866620183584 - 32 -0 - 13 -3439.409960013474 - 23 -1252.866620183584 - 33 -0 - 0 -SOLID - 5 -2B8 -100 -AcDbEntity - 8 -BLK_1_FLR_1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3439.379987518114 - 20 -1256.28662018356 - 30 -0 - 11 -3439.409960013474 - 21 -1256.10662018356 - 31 -0 - 12 -3439.350015022754 - 22 -1256.10662018356 - 32 -0 - 13 -3439.350015022754 - 23 -1256.10662018356 - 33 -0 - 0 -LINE - 5 -2B9 -100 -AcDbEntity - 8 -BLK_1_FLR_1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3439.379987518114 - 20 -1254.666620183572 - 11 -3439.379987518114 - 21 -1256.28662018356 - 0 -MTEXT - 5 -2BA -100 -AcDbEntity - 8 -BLK_1_FLR_1_HT_ROOM - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3439.379987518114 - 20 -1254.486620183572 - 30 -0 - 40 -0.18 - 41 -0.7000000000000224 - 71 - 5 - 72 - 1 - 1 -3.6000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2BB -100 -AcDbEntity - 8 -BLK_1_FLR_1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3439.078499989153 - 20 -1252.686620183584 - 11 -3439.559987518114 - 21 -1252.686620183584 - 0 -LINE - 5 -2BC -100 -AcDbEntity - 8 -BLK_1_FLR_1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3440.061276775585 - 20 -1256.28662018356 - 11 -3439.199987518114 - 21 -1256.28662018356 - 0 -ENDBLK - 5 -111 -330 -10F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -113 -330 -112 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D74 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D74 - 1 - - 0 -LINE - 5 -2BD -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3429.255147392662 - 20 -1248.186620183525 - 11 -3429.255147392662 - 21 -1249.055130511409 - 0 -LINE - 5 -2BE -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3429.255147392662 - 20 -1249.055130511409 - 11 -3428.107193445356 - 21 -1249.055130511409 - 0 -SOLID - 5 -2BF -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbTrace - 10 -3429.255147392662 - 20 -1248.186620183525 - 30 -0 - 11 -3429.225174897302 - 21 -1248.366620183525 - 31 -0 - 12 -3429.285119888022 - 22 -1248.366620183525 - 32 -0 - 13 -3429.285119888022 - 23 -1248.366620183525 - 33 -0 - 0 -ENDBLK - 5 -114 -330 -112 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -116 -330 -115 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D13 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D13 - 1 - - 0 -LINE - 5 -2C0 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3698.10208704836 - 20 -1106.992141264977 - 11 -3698.20744350217 - 21 -1106.940119464575 - 0 -LINE - 5 -2C1 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3710.966993896774 - 20 -1133.038190327934 - 11 -3711.072350350584 - 21 -1132.986168527533 - 0 -LINE - 5 -2C2 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3698.046046381887 - 20 -1107.019812435183 - 11 -3704.417486820407 - 21 -1119.919311220429 - 0 -SOLID - 5 -2C3 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3698.046046381887 - 20 -1107.019812435183 - 30 -0 - 11 -3698.098886937757 - 21 -1107.194472751607 - 31 -0 - 12 -3698.15263324307 - 22 -1107.167925876508 - 32 -0 - 13 -3698.15263324307 - 23 -1107.167925876508 - 33 -0 - 0 -SOLID - 5 -2C4 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3710.910953230301 - 20 -1133.06586149814 - 30 -0 - 11 -3710.858112674431 - 21 -1132.891201181716 - 31 -0 - 12 -3710.804366369118 - 22 -1132.917748056815 - 32 -0 - 13 -3710.804366369118 - 23 -1132.917748056815 - 33 -0 - 0 -LINE - 5 -2C5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3704.595301369333 - 20 -1120.279311220429 - 11 -3710.910953230301 - 21 -1133.06586149814 - 0 -MTEXT - 5 -2C6 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3704.36416309136 - 20 -1120.099311220429 - 30 -0 - 40 -0.18 - 41 -0.8400000000000112 - 71 - 5 - 72 - 1 - 1 -29.0500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -117 -330 -115 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -119 -330 -118 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D30 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D30 - 1 - - 0 -LINE - 5 -2C7 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3301.94653896565 - 20 -1245.652369962656 - 11 -3301.94653896565 - 21 -1244.782369962665 - 0 -SOLID - 5 -2C8 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3301.94653896565 - 20 -1245.652369962656 - 30 -0 - 11 -3301.97651146101 - 21 -1245.472369962656 - 31 -0 - 12 -3301.91656647029 - 22 -1245.472369962656 - 32 -0 - 13 -3301.91656647029 - 23 -1245.472369962656 - 33 -0 - 0 -SOLID - 5 -2C9 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3301.94653896565 - 20 -1243.552369962674 - 30 -0 - 11 -3301.91656647029 - 21 -1243.732369962674 - 31 -0 - 12 -3301.97651146101 - 22 -1243.732369962674 - 32 -0 - 13 -3301.97651146101 - 23 -1243.732369962674 - 33 -0 - 0 -LINE - 5 -2CA -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3301.94653896565 - 20 -1244.422369962665 - 11 -3301.94653896565 - 21 -1243.552369962674 - 0 -MTEXT - 5 -2CB -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3301.94653896565 - 20 -1244.602369962665 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -2.1000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2CC -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3302.120498795771 - 20 -1245.652369962656 - 11 -3301.76653896565 - 21 -1245.652369962656 - 0 -LINE - 5 -2CD -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3302.120498795771 - 20 -1243.552369962674 - 11 -3301.76653896565 - 21 -1243.552369962674 - 0 -ENDBLK - 5 -11A -330 -118 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -11C -330 -11B -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D26 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D26 - 1 - - 0 -LINE - 5 -2CE -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3282.378710914939 - 20 -1243.552369962679 - 11 -3282.378710914939 - 21 -1244.572369962662 - 0 -SOLID - 5 -2CF -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3282.378710914939 - 20 -1243.552369962679 - 30 -0 - 11 -3282.348738419579 - 21 -1243.732369962679 - 31 -0 - 12 -3282.408683410299 - 22 -1243.732369962679 - 32 -0 - 13 -3282.408683410299 - 23 -1243.732369962679 - 33 -0 - 0 -SOLID - 5 -2D0 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3282.378710914939 - 20 -1245.952369962645 - 30 -0 - 11 -3282.408683410299 - 21 -1245.772369962645 - 31 -0 - 12 -3282.348738419579 - 22 -1245.772369962645 - 32 -0 - 13 -3282.348738419579 - 23 -1245.772369962645 - 33 -0 - 0 -LINE - 5 -2D1 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3282.378710914939 - 20 -1244.932369962662 - 11 -3282.378710914939 - 21 -1245.952369962645 - 0 -MTEXT - 5 -2D2 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3282.378710914938 - 20 -1244.752369962662 - 30 -0 - 40 -0.18 - 41 -0.72 - 71 - 5 - 72 - 1 - 1 -2.4000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2D3 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3282.378710914928 - 20 -1243.552369962679 - 11 -3282.198710914939 - 21 -1243.552369962679 - 0 -LINE - 5 -2D4 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3282.378710914933 - 20 -1245.952369962645 - 11 -3282.198710914939 - 21 -1245.952369962645 - 0 -ENDBLK - 5 -11D -330 -11B -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -11F -330 -11E -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D90 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D90 - 1 - - 0 -LINE - 5 -2D5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3666.628909456082 - 20 -1160.460084471688 - 11 -3666.532014407246 - 21 -1161.284758896472 - 0 -LINE - 5 -2D6 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3663.301796227977 - 20 -1160.069165596273 - 11 -3663.204901179141 - 21 -1160.893840021057 - 0 -LINE - 5 -2D7 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3666.553019003537 - 20 -1161.105988633468 - 11 -3665.314581399462 - 21 -1160.960478516359 - 0 -SOLID - 5 -2D8 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3666.553019003537 - 20 -1161.105988633468 - 30 -0 - 11 -3666.377746297004 - 21 -1161.055216310075 - 31 -0 - 12 -3666.370751184061 - 22 -1161.114751764279 - 32 -0 - 13 -3666.370751184061 - 23 -1161.114751764279 - 33 -0 - 0 -SOLID - 5 -2D9 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3663.225905775432 - 20 -1160.715069758053 - 30 -0 - 11 -3663.401178481965 - 21 -1160.765842081446 - 31 -0 - 12 -3663.408173594908 - 22 -1160.706306627242 - 32 -0 - 13 -3663.408173594908 - 23 -1160.706306627242 - 33 -0 - 0 -LINE - 5 -2DA -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3664.435418966782 - 20 -1160.857181403839 - 11 -3663.225905775432 - 21 -1160.715069758053 - 0 -MTEXT - 5 -2DB -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3664.874581399463 - 20 -1161.037181403839 - 30 -0 - 40 -0.18 - 41 -0.7000000000000335 - 71 - 5 - 72 - 1 - 1 -3.3500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -120 -330 -11E -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -122 -330 -121 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D47 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D47 - 1 - - 0 -LINE - 5 -2DC -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.088675249515 - 20 -1243.75668465645 - 11 -3352.268675249544 - 21 -1243.75668465645 - 0 -SOLID - 5 -2DD -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3352.088675249515 - 20 -1243.75668465645 - 30 -0 - 11 -3352.268675249515 - 21 -1243.78665715181 - 31 -0 - 12 -3352.268675249515 - 22 -1243.72671216109 - 32 -0 - 13 -3352.268675249515 - 23 -1243.72671216109 - 33 -0 - 0 -SOLID - 5 -2DE -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3353.288675249574 - 20 -1243.75668465645 - 30 -0 - 11 -3353.108675249574 - 21 -1243.72671216109 - 31 -0 - 12 -3353.108675249574 - 22 -1243.78665715181 - 32 -0 - 13 -3353.108675249574 - 23 -1243.78665715181 - 33 -0 - 0 -LINE - 5 -2DF -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.108675249544 - 20 -1243.75668465645 - 11 -3353.288675249574 - 21 -1243.75668465645 - 0 -MTEXT - 5 -2E0 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3352.688675249544 - 20 -1243.75668465645 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2E1 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.088675249515 - 20 -1245.952369962641 - 11 -3352.088675249515 - 21 -1243.57668465645 - 0 -LINE - 5 -2E2 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.288675249574 - 20 -1243.552372614588 - 11 -3353.288675249574 - 21 -1243.93668465645 - 0 -ENDBLK - 5 -123 -330 -121 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -125 -330 -124 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D8 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D8 - 1 - - 0 -LINE - 5 -2E3 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1248.124625565833 - 11 -3299.224289594358 - 21 -1248.124625565833 - 0 -SOLID - 5 -2E4 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.024476717227 - 20 -1248.124625565833 - 30 -0 - 11 -3299.204476717227 - 21 -1248.154598061193 - 31 -0 - 12 -3299.204476717227 - 22 -1248.094653070473 - 32 -0 - 13 -3299.204476717227 - 23 -1248.094653070473 - 33 -0 - 0 -SOLID - 5 -2E5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.22410247149 - 20 -1248.124625565833 - 30 -0 - 11 -3300.04410247149 - 21 -1248.094653070473 - 31 -0 - 12 -3300.04410247149 - 22 -1248.154598061193 - 32 -0 - 13 -3300.04410247149 - 23 -1248.154598061193 - 33 -0 - 0 -LINE - 5 -2E6 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.024289594358 - 20 -1248.124625565833 - 11 -3300.22410247149 - 21 -1248.124625565833 - 0 -MTEXT - 5 -2E7 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3299.624289594358 - 20 -1248.2521489977 - 30 -0 - 40 -0.18 - 41 -0.6200000000000112 - 71 - 5 - 72 - 1 - 1 -1.1996 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2E8 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1247.752369962632 - 11 -3299.024476717227 - 21 -1248.304625565833 - 0 -LINE - 5 -2E9 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1247.752369962632 - 11 -3300.22410247149 - 21 -1248.304625565833 - 0 -ENDBLK - 5 -126 -330 -124 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -128 -330 -127 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D55 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D55 - 1 - - 0 -LINE - 5 -2EA -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.627986023668 - 20 -1258.458460622718 - 11 -3315.877986023473 - 21 -1258.458460622718 - 0 -SOLID - 5 -2EB -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3316.627986023668 - 20 -1258.458460622718 - 30 -0 - 11 -3316.447986023668 - 21 -1258.428488127358 - 31 -0 - 12 -3316.447986023668 - 22 -1258.488433118078 - 32 -0 - 13 -3316.447986023668 - 23 -1258.488433118078 - 33 -0 - 0 -SOLID - 5 -2EC -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3315.877986023473 - 20 -1258.458460622718 - 30 -0 - 11 -3316.057986023473 - 21 -1258.488433118078 - 31 -0 - 12 -3316.057986023473 - 22 -1258.428488127358 - 32 -0 - 13 -3316.057986023473 - 23 -1258.428488127358 - 33 -0 - 0 -MTEXT - 5 -2ED -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3315.234664058943 - 20 -1258.458460622718 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2EE -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.627986023668 - 20 -1258.300104121969 - 11 -3316.627986023668 - 21 -1258.638460622718 - 0 -LINE - 5 -2EF -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3315.877986023473 - 20 -1258.300104121969 - 11 -3315.877986023473 - 21 -1258.638460622718 - 0 -ENDBLK - 5 -129 -330 -127 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -12B -330 -12A -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D73 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D73 - 1 - - 0 -LINE - 5 -2F0 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3431.018724545987 - 20 -1247.78662018356 - 11 -3431.018724545987 - 21 -1246.889261580955 - 0 -SOLID - 5 -2F1 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3431.018724545987 - 20 -1247.78662018356 - 30 -0 - 11 -3431.048697041347 - 21 -1247.60662018356 - 31 -0 - 12 -3430.988752050627 - 22 -1247.60662018356 - 32 -0 - 13 -3430.988752050627 - 23 -1247.60662018356 - 33 -0 - 0 -SOLID - 5 -2F2 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3431.018724545987 - 20 -1245.631902978352 - 30 -0 - 11 -3430.988752050627 - 21 -1245.811902978352 - 31 -0 - 12 -3431.048697041347 - 22 -1245.811902978352 - 32 -0 - 13 -3431.048697041347 - 23 -1245.811902978352 - 33 -0 - 0 -LINE - 5 -2F3 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3431.018724545987 - 20 -1246.529261580955 - 11 -3431.018724545987 - 21 -1245.631902978352 - 0 -MTEXT - 5 -2F4 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3430.89120111412 - 20 -1246.709261580955 - 30 -0 - 40 -0.18 - 41 -0.6800000000000113 - 71 - 5 - 72 - 1 - 1 -2.1547 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2F5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3430.764366980675 - 20 -1247.78662018356 - 11 -3431.198724545987 - 21 -1247.78662018356 - 0 -LINE - 5 -2F6 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3430.764366980675 - 20 -1245.631902978352 - 11 -3431.198724545987 - 21 -1245.631902978352 - 0 -ENDBLK - 5 -12C -330 -12A -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -12E -330 -12D -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D57 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D57 - 1 - - 0 -LINE - 5 -2F7 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.28447671888 - 20 -1258.300104171694 - 11 -3299.28447671888 - 21 -1257.480104146831 - 0 -SOLID - 5 -2F8 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.28447671888 - 20 -1258.300104171694 - 30 -0 - 11 -3299.31444921424 - 21 -1258.120104171694 - 31 -0 - 12 -3299.25450422352 - 22 -1258.120104171694 - 32 -0 - 13 -3299.25450422352 - 23 -1258.120104171694 - 33 -0 - 0 -SOLID - 5 -2F9 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.28447671888 - 20 -1256.300104121969 - 30 -0 - 11 -3299.25450422352 - 21 -1256.480104121969 - 31 -0 - 12 -3299.31444921424 - 22 -1256.480104121969 - 32 -0 - 13 -3299.31444921424 - 23 -1256.480104121969 - 33 -0 - 0 -LINE - 5 -2FA -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.28447671888 - 20 -1257.120104146831 - 11 -3299.28447671888 - 21 -1256.300104121969 - 0 -MTEXT - 5 -2FB -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3299.28447671888 - 20 -1257.300104146831 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -2.0000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2FC -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.257778118009 - 20 -1258.300104171694 - 11 -3299.46447671888 - 21 -1258.300104171694 - 0 -LINE - 5 -2FD -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.284476718866 - 20 -1256.300104121969 - 11 -3299.46447671888 - 21 -1256.300104121969 - 0 -ENDBLK - 5 -12F -330 -12D -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -131 -330 -130 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D5 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D5 - 1 - - 0 -LINE - 5 -2FE -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3281.373068378307 - 20 -1261.079065790865 - 11 -3286.751803563298 - 21 -1261.079065790865 - 0 -SOLID - 5 -2FF -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3281.373068378307 - 20 -1261.079065790865 - 30 -0 - 11 -3281.553068378307 - 21 -1261.109038286225 - 31 -0 - 12 -3281.553068378307 - 22 -1261.049093295505 - 32 -0 - 13 -3281.553068378307 - 23 -1261.049093295505 - 33 -0 - 0 -SOLID - 5 -300 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3293.070538748289 - 20 -1261.079065790865 - 30 -0 - 11 -3292.890538748289 - 21 -1261.049093295505 - 31 -0 - 12 -3292.890538748289 - 22 -1261.109038286225 - 32 -0 - 13 -3292.890538748289 - 23 -1261.109038286225 - 33 -0 - 0 -LINE - 5 -301 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3287.691803563298 - 20 -1261.079065790865 - 11 -3293.070538748289 - 21 -1261.079065790865 - 0 -MTEXT - 5 -302 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3287.221803563298 - 20 -1261.206589222733 - 30 -0 - 40 -0.18 - 41 -0.7600000000000224 - 71 - 5 - 72 - 1 - 1 -11.6975 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -303 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3281.373068378307 - 20 -1259.280104148725 - 11 -3281.373068378307 - 21 -1261.259065790865 - 0 -LINE - 5 -304 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3293.070538748289 - 20 -1259.280104148725 - 11 -3293.070538748289 - 21 -1261.259065790865 - 0 -ENDBLK - 5 -132 -330 -130 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -134 -330 -133 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D52 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D52 - 1 - - 0 -LINE - 5 -305 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.223767729391 - 20 -1258.300104171694 - 11 -3317.223767729391 - 21 -1257.480104146831 - 0 -SOLID - 5 -306 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.223767729391 - 20 -1258.300104171694 - 30 -0 - 11 -3317.253740224751 - 21 -1258.120104171694 - 31 -0 - 12 -3317.193795234031 - 22 -1258.120104171694 - 32 -0 - 13 -3317.193795234031 - 23 -1258.120104171694 - 33 -0 - 0 -SOLID - 5 -307 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.223767729391 - 20 -1256.300104121969 - 30 -0 - 11 -3317.193795234031 - 21 -1256.480104121969 - 31 -0 - 12 -3317.253740224751 - 22 -1256.480104121969 - 32 -0 - 13 -3317.253740224751 - 23 -1256.480104121969 - 33 -0 - 0 -LINE - 5 -308 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.223767729391 - 20 -1257.120104146831 - 11 -3317.223767729391 - 21 -1256.300104121969 - 0 -MTEXT - 5 -309 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3317.223767729391 - 20 -1257.300104146831 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -2.0000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -30A -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.102986023332 - 20 -1258.300104171694 - 11 -3317.403767729391 - 21 -1258.300104171694 - 0 -LINE - 5 -30B -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.102986023332 - 20 -1256.300104121969 - 11 -3317.403767729391 - 21 -1256.300104121969 - 0 -ENDBLK - 5 -135 -330 -133 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -137 -330 -136 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D16 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D16 - 1 - - 0 -LINE - 5 -30C -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3695.052411675178 - 20 -1112.562226008124 - 11 -3695.513967730656 - 21 -1109.802356924703 - 0 -SOLID - 5 -30D -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3695.052411675178 - 20 -1112.562226008124 - 30 -0 - 11 -3695.11166418721 - 21 -1112.389635480296 - 31 -0 - 12 -3695.052540303212 - 22 -1112.379747697268 - 32 -0 - 13 -3695.052540303212 - 23 -1112.379747697268 - 33 -0 - 0 -SOLID - 5 -30E -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3696.042765219429 - 20 -1106.640418470341 - 30 -0 - 11 -3695.983512707397 - 21 -1106.813008998169 - 31 -0 - 12 -3696.042636591395 - 22 -1106.822896781197 - 32 -0 - 13 -3696.042636591395 - 23 -1106.822896781197 - 33 -0 - 0 -LINE - 5 -30F -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3695.574173550189 - 20 -1109.442356924703 - 11 -3696.042765219429 - 21 -1106.640418470341 - 0 -MTEXT - 5 -310 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3695.673365105243 - 20 -1109.622356924703 - 30 -0 - 40 -0.18 - 41 -0.7200000000000111 - 71 - 5 - 72 - 1 - 1 -6.0040 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -311 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3695.126580710478 - 20 -1112.574629917997 - 11 -3694.874877255836 - 21 -1112.532535438091 - 0 -LINE - 5 -312 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3696.042765217587 - 20 -1106.640418470033 - 11 -3695.865230800087 - 21 -1106.610727900308 - 0 -ENDBLK - 5 -138 -330 -136 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -13A -330 -139 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D2 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D2 - 1 - - 0 -LINE - 5 -313 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3287.850942810532 - 20 -1243.423737554054 - 11 -3287.850942810532 - 21 -1241.416164394351 - 0 -LINE - 5 -314 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3287.850942810532 - 20 -1241.416164394351 - 11 -3286.261099679629 - 21 -1241.416164394351 - 0 -SOLID - 5 -315 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbTrace - 10 -3287.850942810532 - 20 -1243.423737554054 - 30 -0 - 11 -3287.880915305892 - 21 -1243.243737554054 - 31 -0 - 12 -3287.820970315172 - 22 -1243.243737554054 - 32 -0 - 13 -3287.820970315172 - 23 -1243.243737554054 - 33 -0 - 0 -ENDBLK - 5 -13B -330 -139 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -13D -330 -13C -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D6 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D6 - 1 - - 0 -LINE - 5 -316 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3294.049122274159 - 20 -1259.280104148725 - 11 -3294.049122274159 - 21 -1252.796237055684 - 0 -SOLID - 5 -317 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3294.049122274159 - 20 -1259.280104148725 - 30 -0 - 11 -3294.079094769519 - 21 -1259.100104148725 - 31 -0 - 12 -3294.019149778799 - 22 -1259.100104148725 - 32 -0 - 13 -3294.019149778799 - 23 -1259.100104148725 - 33 -0 - 0 -SOLID - 5 -318 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3294.049122274159 - 20 -1245.952369962644 - 30 -0 - 11 -3294.019149778799 - 21 -1246.132369962644 - 31 -0 - 12 -3294.079094769519 - 22 -1246.132369962644 - 32 -0 - 13 -3294.079094769519 - 23 -1246.132369962644 - 33 -0 - 0 -LINE - 5 -319 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3294.049122274159 - 20 -1252.436237055684 - 11 -3294.049122274159 - 21 -1245.952369962644 - 0 -MTEXT - 5 -31A -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3293.921598842291 - 20 -1252.616237055684 - 30 -0 - 40 -0.18 - 41 -0.8000000000000224 - 71 - 5 - 72 - 1 - 1 -13.3277 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -31B -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3293.070538748289 - 20 -1259.280104148725 - 11 -3294.229122274159 - 21 -1259.280104148725 - 0 -LINE - 5 -31C -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3293.070538748289 - 20 -1245.952369962644 - 11 -3294.229122274159 - 21 -1245.952369962644 - 0 -ENDBLK - 5 -13E -330 -13C -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -140 -330 -13F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D38 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D38 - 1 - - 0 -LINE - 5 -31D -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.663978740904 - 20 -1243.552369960933 - 11 -3316.663978740904 - 21 -1245.0223699618 - 0 -SOLID - 5 -31E -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3316.663978740904 - 20 -1243.552369960933 - 30 -0 - 11 -3316.634006245544 - 21 -1243.732369960933 - 31 -0 - 12 -3316.693951236264 - 22 -1243.732369960933 - 32 -0 - 13 -3316.693951236264 - 23 -1243.732369960933 - 33 -0 - 0 -SOLID - 5 -31F -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3316.663978740904 - 20 -1246.852369962667 - 30 -0 - 11 -3316.693951236264 - 21 -1246.672369962667 - 31 -0 - 12 -3316.634006245544 - 22 -1246.672369962667 - 32 -0 - 13 -3316.634006245544 - 23 -1246.672369962667 - 33 -0 - 0 -LINE - 5 -320 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.663978740904 - 20 -1245.3823699618 - 11 -3316.663978740904 - 21 -1246.852369962667 - 0 -MTEXT - 5 -321 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3316.663978740903 - 20 -1245.2023699618 - 30 -0 - 40 -0.18 - 41 -0.7000000000000224 - 71 - 5 - 72 - 1 - 1 -3.3000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -322 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.663978740885 - 20 -1243.552369960933 - 11 -3316.483978740904 - 21 -1243.552369960933 - 0 -LINE - 5 -323 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.663978740891 - 20 -1246.852369962667 - 11 -3316.483978740904 - 21 -1246.852369962667 - 0 -ENDBLK - 5 -141 -330 -13F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -143 -330 -142 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D87 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D87 - 1 - - 0 -LINE - 5 -324 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.004476717158 - 20 -1259.050104148744 - 11 -3300.004476717158 - 21 -1258.300104148744 - 0 -SOLID - 5 -325 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.004476717158 - 20 -1259.050104148744 - 30 -0 - 11 -3300.034449212518 - 21 -1258.870104148744 - 31 -0 - 12 -3299.974504221798 - 22 -1258.870104148744 - 32 -0 - 13 -3299.974504221798 - 23 -1258.870104148744 - 33 -0 - 0 -SOLID - 5 -326 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.004476717158 - 20 -1258.300104148744 - 30 -0 - 11 -3299.974504221798 - 21 -1258.480104148744 - 31 -0 - 12 -3300.034449212518 - 22 -1258.480104148744 - 32 -0 - 13 -3300.034449212518 - 23 -1258.480104148744 - 33 -0 - 0 -MTEXT - 5 -327 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3299.361154752628 - 20 -1258.120104148744 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -328 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.824476717156 - 20 -1259.050104148744 - 11 -3300.184476717158 - 21 -1259.050104148744 - 0 -LINE - 5 -329 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.004476717158 - 20 -1258.300104148744 - 11 -3300.184476717158 - 21 -1258.300104148744 - 0 -ENDBLK - 5 -144 -330 -142 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -146 -330 -145 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D36 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D36 - 1 - - 0 -LINE - 5 -32A -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3318.800048270567 - 20 -1245.652369962656 - 11 -3318.800048270567 - 21 -1244.782369961795 - 0 -SOLID - 5 -32B -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3318.800048270567 - 20 -1245.652369962656 - 30 -0 - 11 -3318.830020765927 - 21 -1245.472369962656 - 31 -0 - 12 -3318.770075775207 - 22 -1245.472369962656 - 32 -0 - 13 -3318.770075775207 - 23 -1245.472369962656 - 33 -0 - 0 -SOLID - 5 -32C -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3318.800048270567 - 20 -1243.552369960933 - 30 -0 - 11 -3318.770075775207 - 21 -1243.732369960933 - 31 -0 - 12 -3318.830020765927 - 22 -1243.732369960933 - 32 -0 - 13 -3318.830020765927 - 23 -1243.732369960933 - 33 -0 - 0 -LINE - 5 -32D -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3318.800048270567 - 20 -1244.422369961795 - 11 -3318.800048270567 - 21 -1243.552369960933 - 0 -MTEXT - 5 -32E -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3318.800048270566 - 20 -1244.602369961795 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -2.1000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -32F -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3318.97400810069 - 20 -1245.652369962656 - 11 -3318.620048270567 - 21 -1245.652369962656 - 0 -LINE - 5 -330 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3318.97400810071 - 20 -1243.552369960933 - 11 -3318.620048270567 - 21 -1243.552369960933 - 0 -ENDBLK - 5 -147 -330 -145 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -149 -330 -148 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D27 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D27 - 1 - - 0 -LINE - 5 -331 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.703068378148 - 20 -1245.209053745057 - 11 -3283.883068378125 - 21 -1245.209053745057 - 0 -SOLID - 5 -332 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3283.703068378148 - 20 -1245.209053745057 - 30 -0 - 11 -3283.883068378148 - 21 -1245.239026240417 - 31 -0 - 12 -3283.883068378148 - 22 -1245.179081249697 - 32 -0 - 13 -3283.883068378148 - 23 -1245.179081249697 - 33 -0 - 0 -SOLID - 5 -333 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3284.903068378103 - 20 -1245.209053745057 - 30 -0 - 11 -3284.723068378103 - 21 -1245.179081249697 - 31 -0 - 12 -3284.723068378103 - 22 -1245.239026240417 - 32 -0 - 13 -3284.723068378103 - 23 -1245.239026240417 - 33 -0 - 0 -LINE - 5 -334 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3284.723068378125 - 20 -1245.209053745057 - 11 -3284.903068378103 - 21 -1245.209053745057 - 0 -MTEXT - 5 -335 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3284.303068378125 - 20 -1245.209053745057 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -336 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.703068378148 - 20 -1245.052369962679 - 11 -3283.703068378148 - 21 -1245.389053745057 - 0 -LINE - 5 -337 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3284.903068378103 - 20 -1245.052369962679 - 11 -3284.903068378103 - 21 -1245.389053745057 - 0 -ENDBLK - 5 -14A -330 -148 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -14C -330 -14B -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D3 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D3 - 1 - - 0 -LINE - 5 -338 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3288.623488413138 - 20 -1243.623737554066 - 11 -3288.623488413138 - 21 -1251.271920851396 - 0 -SOLID - 5 -339 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3288.623488413138 - 20 -1243.623737554066 - 30 -0 - 11 -3288.593515917778 - 21 -1243.803737554066 - 31 -0 - 12 -3288.653460908498 - 22 -1243.803737554066 - 32 -0 - 13 -3288.653460908498 - 23 -1243.803737554066 - 33 -0 - 0 -SOLID - 5 -33A -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3288.623488413138 - 20 -1259.280104148725 - 30 -0 - 11 -3288.653460908498 - 21 -1259.100104148725 - 31 -0 - 12 -3288.593515917778 - 22 -1259.100104148725 - 32 -0 - 13 -3288.593515917778 - 23 -1259.100104148725 - 33 -0 - 0 -LINE - 5 -33B -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3288.623488413138 - 20 -1251.631920851396 - 11 -3288.623488413138 - 21 -1259.280104148725 - 0 -MTEXT - 5 -33C -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3288.495964981269 - 20 -1251.451920851396 - 30 -0 - 40 -0.18 - 41 -0.8200000000000447 - 71 - 5 - 72 - 1 - 1 -15.6564 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -33D -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3287.835900044962 - 20 -1243.623737554066 - 11 -3288.803488413138 - 21 -1243.623737554066 - 0 -LINE - 5 -33E -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3287.835900044962 - 20 -1259.280104148725 - 11 -3288.803488413138 - 21 -1259.280104148725 - 0 -ENDBLK - 5 -14D -330 -14B -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -14F -330 -14E -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D20 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D20 - 1 - - 0 -LINE - 5 -33F -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3690.568945564359 - 20 -1105.614665471137 - 11 -3691.528679997723 - 21 -1099.875944551971 - 0 -SOLID - 5 -340 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3690.568945564359 - 20 -1105.614665471137 - 30 -0 - 11 -3690.628198076392 - 21 -1105.442074943309 - 31 -0 - 12 -3690.569074192393 - 22 -1105.432187160281 - 32 -0 - 13 -3690.569074192393 - 23 -1105.432187160281 - 33 -0 - 0 -SOLID - 5 -341 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3692.548620250619 - 20 -1093.777223632806 - 30 -0 - 11 -3692.489367738587 - 21 -1093.949814160634 - 31 -0 - 12 -3692.548491622586 - 22 -1093.959701943662 - 32 -0 - 13 -3692.548491622586 - 23 -1093.959701943662 - 33 -0 - 0 -LINE - 5 -342 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3691.588885817256 - 20 -1099.515944551971 - 11 -3692.548620250619 - 21 -1093.777223632806 - 0 -MTEXT - 5 -343 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3691.55878290749 - 20 -1099.695944551971 - 30 -0 - 40 -0.18 - 41 -0.76 - 71 - 5 - 72 - 1 - 1 -12.0018 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -344 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3690.101075426844 - 20 -1105.536419623736 - 11 -3690.746479983701 - 21 -1105.64435604117 - 0 -LINE - 5 -345 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3692.167267226776 - 20 -1093.713446767995 - 11 -3692.726154669961 - 21 -1093.806914202839 - 0 -ENDBLK - 5 -150 -330 -14E -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -152 -330 -151 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D7 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D7 - 1 - - 0 -LINE - 5 -346 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3280.402680748146 - 20 -1242.154635776649 - 11 -3280.402680748146 - 21 -1250.537369962687 - 0 -SOLID - 5 -347 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3280.402680748146 - 20 -1242.154635776649 - 30 -0 - 11 -3280.372708252786 - 21 -1242.334635776649 - 31 -0 - 12 -3280.432653243506 - 22 -1242.334635776649 - 32 -0 - 13 -3280.432653243506 - 23 -1242.334635776649 - 33 -0 - 0 -SOLID - 5 -348 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3280.402680748146 - 20 -1259.280104148725 - 30 -0 - 11 -3280.432653243506 - 21 -1259.100104148725 - 31 -0 - 12 -3280.372708252786 - 22 -1259.100104148725 - 32 -0 - 13 -3280.372708252786 - 23 -1259.100104148725 - 33 -0 - 0 -LINE - 5 -349 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3280.402680748146 - 20 -1250.897369962687 - 11 -3280.402680748146 - 21 -1259.280104148725 - 0 -MTEXT - 5 -34A -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3280.275157316278 - 20 -1250.717369962687 - 30 -0 - 40 -0.18 - 41 -0.7600000000000222 - 71 - 5 - 72 - 1 - 1 -17.1255 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -34B -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3281.373068378307 - 20 -1242.154635776649 - 11 -3280.222680748146 - 21 -1242.154635776649 - 0 -LINE - 5 -34C -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3281.373068378307 - 20 -1259.280104148725 - 11 -3280.222680748146 - 21 -1259.280104148725 - 0 -ENDBLK - 5 -153 -330 -151 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -155 -330 -154 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D58 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D58 - 1 - - 0 -LINE - 5 -34D -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1258.430923504448 - 11 -3300.624476718716 - 21 -1258.430923504448 - 0 -SOLID - 5 -34E -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.874476717086 - 20 -1258.430923504448 - 30 -0 - 11 -3300.054476717086 - 21 -1258.460895999808 - 31 -0 - 12 -3300.054476717086 - 22 -1258.400951009088 - 32 -0 - 13 -3300.054476717086 - 23 -1258.400951009088 - 33 -0 - 0 -SOLID - 5 -34F -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.624476718716 - 20 -1258.430923504448 - 30 -0 - 11 -3300.444476718716 - 21 -1258.400951009088 - 31 -0 - 12 -3300.444476718716 - 22 -1258.460895999808 - 32 -0 - 13 -3300.444476718716 - 23 -1258.460895999808 - 33 -0 - 0 -MTEXT - 5 -350 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3301.267798683246 - 20 -1258.430923504448 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -351 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1258.300104171694 - 11 -3299.874476717086 - 21 -1258.610923504448 - 0 -LINE - 5 -352 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.624476718716 - 20 -1258.300104171694 - 11 -3300.624476718716 - 21 -1258.610923504448 - 0 -ENDBLK - 5 -156 -330 -154 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -158 -330 -157 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D81 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D81 - 1 - - 0 -LINE - 5 -353 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3429.547647392643 - 20 -1248.186620183525 - 11 -3430.191031889974 - 21 -1248.186620183525 - 0 -LINE - 5 -354 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3429.547647392643 - 20 -1246.989735042331 - 11 -3430.191031889974 - 21 -1246.989735042331 - 0 -LINE - 5 -355 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3430.011031889974 - 20 -1248.186620183525 - 11 -3430.011031889974 - 21 -1247.768177612927 - 0 -SOLID - 5 -356 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3430.011031889974 - 20 -1248.186620183525 - 30 -0 - 11 -3430.041004385334 - 21 -1248.006620183525 - 31 -0 - 12 -3429.981059394614 - 22 -1248.006620183525 - 32 -0 - 13 -3429.981059394614 - 23 -1248.006620183525 - 33 -0 - 0 -SOLID - 5 -357 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3430.011031889974 - 20 -1246.989735042331 - 30 -0 - 11 -3429.981059394614 - 21 -1247.169735042331 - 31 -0 - 12 -3430.041004385334 - 22 -1247.169735042331 - 32 -0 - 13 -3430.041004385334 - 23 -1247.169735042331 - 33 -0 - 0 -LINE - 5 -358 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3430.011031889974 - 20 -1247.408177612927 - 11 -3430.011031889974 - 21 -1246.989735042331 - 0 -MTEXT - 5 -359 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3429.883508458106 - 20 -1247.588177612927 - 30 -0 - 40 -0.18 - 41 -0.6200000000000112 - 71 - 5 - 72 - 1 - 1 -1.1969 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -159 -330 -157 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -15B -330 -15A -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D11 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D11 - 1 - - 0 -LINE - 5 -35A -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3701.362999543092 - 20 -1133.283221728451 - 11 -3701.375225701095 - 21 -1134.089105985646 - 0 -LINE - 5 -35B -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3710.911900706631 - 20 -1133.138354306928 - 11 -3710.924126864634 - 21 -1133.944238564123 - 0 -LINE - 5 -35C -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3701.372495215663 - 20 -1133.909126696701 - 11 -3705.708880246726 - 21 -1133.84333892621 - 0 -SOLID - 5 -35D -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3701.372495215663 - 20 -1133.909126696701 - 30 -0 - 11 -3701.552929168286 - 21 -1133.936365257951 - 31 -0 - 12 -3701.552019840931 - 22 -1133.876427164587 - 32 -0 - 13 -3701.552019840931 - 23 -1133.876427164587 - 33 -0 - 0 -SOLID - 5 -35E -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3710.921396379202 - 20 -1133.764259275178 - 30 -0 - 11 -3710.740962426579 - 21 -1133.737020713928 - 31 -0 - 12 -3710.741871753934 - 22 -1133.796958807292 - 32 -0 - 13 -3710.741871753934 - 23 -1133.796958807292 - 33 -0 - 0 -LINE - 5 -35F -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3706.588880246726 - 20 -1133.829988350185 - 11 -3710.921396379202 - 21 -1133.764259275178 - 0 -MTEXT - 5 -360 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3706.148880246726 - 20 -1133.964201744781 - 30 -0 - 40 -0.18 - 41 -0.7000000000000337 - 71 - 5 - 72 - 1 - 1 -9.5500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -15C -330 -15A -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -15E -330 -15D -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D62 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D62 - 1 - - 0 -LINE - 5 -361 -100 -AcDbEntity - 8 -DIST_EXIT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.595899450548 - 20 -1256.244520042979 - 11 -3300.234382164151 - 21 -1255.541352531269 - 0 -LINE - 5 -362 -100 -AcDbEntity - 8 -DIST_EXIT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3310.233369820708 - 20 -1251.289637916136 - 11 -3309.871852534311 - 21 -1250.586470404426 - 0 -LINE - 5 -363 -100 -AcDbEntity - 8 -DIST_EXIT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.316684691782 - 20 -1255.701434678761 - 11 -3304.785311716421 - 21 -1253.40399361534 - 0 -SOLID - 5 -364 -100 -AcDbEntity - 8 -DIST_EXIT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.316684691782 - 20 -1255.701434678761 - 30 -0 - 11 -3300.490471351093 - 21 -1255.645788047924 - 31 -0 - 12 -3300.463062327454 - 22 -1255.592476254337 - 32 -0 - 13 -3300.463062327454 - 23 -1255.592476254337 - 33 -0 - 0 -SOLID - 5 -365 -100 -AcDbEntity - 8 -DIST_EXIT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3309.954155061942 - 20 -1250.746552551918 - 30 -0 - 11 -3309.780368402631 - 21 -1250.802199182755 - 31 -0 - 12 -3309.80777742627 - 22 -1250.855510976343 - 32 -0 - 13 -3309.80777742627 - 23 -1250.855510976343 - 33 -0 - 0 -LINE - 5 -366 -100 -AcDbEntity - 8 -DIST_EXIT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3305.485528037302 - 20 -1253.04399361534 - 11 -3309.954155061942 - 21 -1250.746552551918 - 0 -MTEXT - 5 -367 -100 -AcDbEntity - 8 -DIST_EXIT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3305.135419876862 - 20 -1253.22399361534 - 30 -0 - 40 -0.18 - 41 -0.8000000000000336 - 71 - 5 - 72 - 1 - 1 -10.8366 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -15F -330 -15D -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -161 -330 -160 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D42 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D42 - 1 - - 0 -LINE - 5 -368 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3355.010737497922 - 20 -1245.652369962656 - 11 -3355.010737497922 - 21 -1244.782369962665 - 0 -SOLID - 5 -369 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3355.010737497922 - 20 -1245.652369962656 - 30 -0 - 11 -3355.040709993282 - 21 -1245.472369962656 - 31 -0 - 12 -3354.980765002562 - 22 -1245.472369962656 - 32 -0 - 13 -3354.980765002562 - 23 -1245.472369962656 - 33 -0 - 0 -SOLID - 5 -36A -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3355.010737497922 - 20 -1243.552369962674 - 30 -0 - 11 -3354.980765002562 - 21 -1243.732369962674 - 31 -0 - 12 -3355.040709993282 - 22 -1243.732369962674 - 32 -0 - 13 -3355.040709993282 - 23 -1243.732369962674 - 33 -0 - 0 -LINE - 5 -36B -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3355.010737497922 - 20 -1244.422369962665 - 11 -3355.010737497922 - 21 -1243.552369962674 - 0 -MTEXT - 5 -36C -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3355.010737497922 - 20 -1244.602369962665 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -2.1000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -36D -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3355.18469732804 - 20 -1245.652369962656 - 11 -3354.830737497922 - 21 -1245.652369962656 - 0 -LINE - 5 -36E -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3355.18469732804 - 20 -1243.552369962674 - 11 -3354.830737497922 - 21 -1243.552369962674 - 0 -ENDBLK - 5 -162 -330 -160 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -164 -330 -163 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D77 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D77 - 1 - - 0 -LINE - 5 -36F -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.52223736918 - 20 -1248.636620183537 - 11 -3427.52223736918 - 21 -1250.481622577436 - 0 -SOLID - 5 -370 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.52223736918 - 20 -1248.636620183537 - 30 -0 - 11 -3427.49226487382 - 21 -1248.816620183537 - 31 -0 - 12 -3427.55220986454 - 22 -1248.816620183537 - 32 -0 - 13 -3427.55220986454 - 23 -1248.816620183537 - 33 -0 - 0 -SOLID - 5 -371 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.52223736918 - 20 -1252.686624971338 - 30 -0 - 11 -3427.55220986454 - 21 -1252.506624971338 - 31 -0 - 12 -3427.49226487382 - 22 -1252.506624971338 - 32 -0 - 13 -3427.49226487382 - 23 -1252.506624971338 - 33 -0 - 0 -LINE - 5 -372 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.52223736918 - 20 -1250.841622577436 - 11 -3427.52223736918 - 21 -1252.686624971338 - 0 -MTEXT - 5 -373 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3427.394713937312 - 20 -1250.661622577436 - 30 -0 - 40 -0.18 - 41 -0.7200000000000111 - 71 - 5 - 72 - 1 - 1 -4.0500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -374 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.762429444553 - 20 -1248.636620183537 - 11 -3427.34223736918 - 21 -1248.636620183537 - 0 -LINE - 5 -375 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.994593221313 - 20 -1252.686624971338 - 11 -3427.34223736918 - 21 -1252.686624971338 - 0 -ENDBLK - 5 -165 -330 -163 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -167 -330 -166 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D17 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D17 - 1 - - 0 -LINE - 5 -376 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3682.788987350215 - 20 -1110.511310697658 - 11 -3683.277497859675 - 21 -1107.5902677691 - 0 -SOLID - 5 -377 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3682.788987350215 - 20 -1110.511310697658 - 30 -0 - 11 -3682.848239862247 - 21 -1110.33872016983 - 31 -0 - 12 -3682.789115978248 - 22 -1110.328832386802 - 32 -0 - 13 -3682.789115978248 - 23 -1110.328832386802 - 33 -0 - 0 -SOLID - 5 -378 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3683.833249802431 - 20 -1104.267155469601 - 30 -0 - 11 -3683.773997290399 - 21 -1104.439745997429 - 31 -0 - 12 -3683.833121174398 - 22 -1104.449633780457 - 32 -0 - 13 -3683.833121174398 - 23 -1104.449633780457 - 33 -0 - 0 -LINE - 5 -379 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3683.337703679209 - 20 -1107.2302677691 - 11 -3683.833249802431 - 21 -1104.267155469601 - 0 -MTEXT - 5 -37A -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3683.436895234262 - 20 -1107.4102677691 - 30 -0 - 40 -0.18 - 41 -0.7000000000000335 - 71 - 5 - 72 - 1 - 1 -6.3309 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -37B -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3682.788987348374 - 20 -1110.51131069735 - 11 -3682.611452930873 - 21 -1110.481620127625 - 0 -LINE - 5 -37C -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3683.833249800589 - 20 -1104.267155469293 - 11 -3683.655715383089 - 21 -1104.237464899568 - 0 -ENDBLK - 5 -168 -330 -166 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -16A -330 -169 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D18 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D18 - 1 - - 0 -LINE - 5 -37D -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3715.716213430494 - 20 -1117.590407744046 - 11 -3716.260409676698 - 21 -1114.336392598132 - 0 -SOLID - 5 -37E -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3715.716213430494 - 20 -1117.590407744046 - 30 -0 - 11 -3715.775465942526 - 21 -1117.417817216219 - 31 -0 - 12 -3715.716342058527 - 22 -1117.40792943319 - 32 -0 - 13 -3715.716342058527 - 23 -1117.40792943319 - 33 -0 - 0 -SOLID - 5 -37F -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3716.871847356197 - 20 -1110.680308081277 - 30 -0 - 11 -3716.812594844165 - 21 -1110.852898609105 - 31 -0 - 12 -3716.871718728164 - 22 -1110.862786392134 - 32 -0 - 13 -3716.871718728164 - 23 -1110.862786392134 - 33 -0 - 0 -LINE - 5 -380 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3716.320615496231 - 20 -1113.976392598132 - 11 -3716.871847356197 - 21 -1110.680308081277 - 0 -MTEXT - 5 -381 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3716.419807051285 - 20 -1114.156392598132 - 30 -0 - 40 -0.18 - 41 -0.6600000000000112 - 71 - 5 - 72 - 1 - 1 -7.0061 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -382 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3715.527812990941 - 20 -1117.558899958314 - 11 -3715.893747849836 - 21 -1117.620098314079 - 0 -LINE - 5 -383 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3716.546538312589 - 20 -1110.625903921355 - 11 -3717.049381775539 - 21 -1110.70999865131 - 0 -ENDBLK - 5 -16B -330 -169 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -16D -330 -16C -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D56 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D56 - 1 - - 0 -LINE - 5 -384 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.370258424579 - 20 -1258.300104171694 - 11 -3300.370258424579 - 21 -1257.480104146831 - 0 -SOLID - 5 -385 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.370258424579 - 20 -1258.300104171694 - 30 -0 - 11 -3300.400230919939 - 21 -1258.120104171694 - 31 -0 - 12 -3300.340285929219 - 22 -1258.120104171694 - 32 -0 - 13 -3300.340285929219 - 23 -1258.120104171694 - 33 -0 - 0 -SOLID - 5 -386 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.370258424579 - 20 -1256.300104121969 - 30 -0 - 11 -3300.340285929219 - 21 -1256.480104121969 - 31 -0 - 12 -3300.400230919939 - 22 -1256.480104121969 - 32 -0 - 13 -3300.400230919939 - 23 -1256.480104121969 - 33 -0 - 0 -LINE - 5 -387 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.370258424579 - 20 -1257.120104146831 - 11 -3300.370258424579 - 21 -1256.300104121969 - 0 -MTEXT - 5 -388 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3300.370258424579 - 20 -1257.300104146831 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -2.0000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -389 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.24947671852 - 20 -1258.300104171694 - 11 -3300.550258424579 - 21 -1258.300104171694 - 0 -LINE - 5 -38A -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.24947671852 - 20 -1256.300104121969 - 11 -3300.550258424579 - 21 -1256.300104121969 - 0 -ENDBLK - 5 -16E -330 -16C -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -170 -330 -16F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D22 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D22 - 1 - - 0 -LINE - 5 -38B -100 -AcDbEntity - 8 -SHORTEST_DIST_TO_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3703.119425063774 - 20 -1113.911337638816 - 11 -3703.563136378727 - 21 -1111.258170974501 - 0 -SOLID - 5 -38C -100 -AcDbEntity - 8 -SHORTEST_DIST_TO_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3703.119425063774 - 20 -1113.911337638816 - 30 -0 - 11 -3703.178677575806 - 21 -1113.738747110988 - 31 -0 - 12 -3703.119553691807 - 22 -1113.72885932796 - 32 -0 - 13 -3703.119553691807 - 23 -1113.72885932796 - 33 -0 - 0 -SOLID - 5 -38D -100 -AcDbEntity - 8 -SHORTEST_DIST_TO_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3704.067053513214 - 20 -1108.245004310186 - 30 -0 - 11 -3704.007801001182 - 21 -1108.417594838014 - 31 -0 - 12 -3704.06692488518 - 22 -1108.427482621042 - 32 -0 - 13 -3704.06692488518 - 23 -1108.427482621042 - 33 -0 - 0 -LINE - 5 -38E -100 -AcDbEntity - 8 -SHORTEST_DIST_TO_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3703.62334219826 - 20 -1110.898170974501 - 11 -3704.067053513214 - 21 -1108.245004310186 - 0 -MTEXT - 5 -38F -100 -AcDbEntity - 8 -SHORTEST_DIST_TO_ROAD - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3703.593239288494 - 20 -1111.078170974501 - 30 -0 - 40 -0.18 - 41 -0.7200000000000224 - 71 - 5 - 72 - 1 - 1 -5.7450 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -390 -100 -AcDbEntity - 8 -SHORTEST_DIST_TO_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3702.893813337845 - 20 -1113.87360669755 - 11 -3703.296959483116 - 21 -1113.941028208849 - 0 -LINE - 5 -391 -100 -AcDbEntity - 8 -SHORTEST_DIST_TO_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3703.84242825261 - 20 -1108.20743834379 - 11 -3704.244587932556 - 21 -1108.274694880219 - 0 -ENDBLK - 5 -171 -330 -16F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -173 -330 -172 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D49 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D49 - 1 - - 0 -LINE - 5 -392 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.348675251248 - 20 -1258.300104171694 - 11 -3352.348675251248 - 21 -1257.480104146832 - 0 -SOLID - 5 -393 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3352.348675251248 - 20 -1258.300104171694 - 30 -0 - 11 -3352.378647746608 - 21 -1258.120104171694 - 31 -0 - 12 -3352.318702755888 - 22 -1258.120104171694 - 32 -0 - 13 -3352.318702755888 - 23 -1258.120104171694 - 33 -0 - 0 -SOLID - 5 -394 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3352.348675251248 - 20 -1256.300104121969 - 30 -0 - 11 -3352.318702755888 - 21 -1256.480104121969 - 31 -0 - 12 -3352.378647746608 - 22 -1256.480104121969 - 32 -0 - 13 -3352.378647746608 - 23 -1256.480104121969 - 33 -0 - 0 -LINE - 5 -395 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.348675251248 - 20 -1257.120104146832 - 11 -3352.348675251248 - 21 -1256.300104121969 - 0 -MTEXT - 5 -396 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3352.348675251248 - 20 -1257.300104146832 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -2.0000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -397 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.321976650384 - 20 -1258.300104171694 - 11 -3352.528675251248 - 21 -1258.300104171694 - 0 -LINE - 5 -398 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.348675251239 - 20 -1256.300104121969 - 11 -3352.528675251248 - 21 -1256.300104121969 - 0 -ENDBLK - 5 -174 -330 -172 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -176 -330 -175 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D60 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D60 - 1 - - 0 -LINE - 5 -399 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3319.629717898161 - 20 -1257.851297607682 - 11 -3319.741621811485 - 21 -1257.851297607682 - 0 -SOLID - 5 -39A -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3319.629717898161 - 20 -1257.851297607682 - 30 -0 - 11 -3319.809717898161 - 21 -1257.881270103042 - 31 -0 - 12 -3319.809717898161 - 22 -1257.821325112322 - 32 -0 - 13 -3319.809717898161 - 23 -1257.821325112322 - 33 -0 - 0 -SOLID - 5 -39B -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3320.693525724812 - 20 -1257.851297607682 - 30 -0 - 11 -3320.513525724812 - 21 -1257.821325112322 - 31 -0 - 12 -3320.513525724812 - 22 -1257.881270103042 - 32 -0 - 13 -3320.513525724812 - 23 -1257.881270103042 - 33 -0 - 0 -LINE - 5 -39C -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3320.581621811486 - 20 -1257.851297607682 - 11 -3320.693525724812 - 21 -1257.851297607682 - 0 -MTEXT - 5 -39D -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3320.161621811486 - 20 -1257.851297607682 - 30 -0 - 40 -0.18 - 41 -0.6600000000000223 - 71 - 5 - 72 - 1 - 1 -1.0638 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -39E -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3319.629717898161 - 20 -1257.867062992372 - 11 -3319.629717898161 - 21 -1257.671297607682 - 0 -LINE - 5 -39F -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3320.693525724812 - 20 -1257.867062992372 - 11 -3320.693525724812 - 21 -1257.671297607682 - 0 -ENDBLK - 5 -177 -330 -175 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -179 -330 -178 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D33 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D33 - 1 - - 0 -LINE - 5 -3A0 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3301.124476717212 - 20 -1245.809053745033 - 11 -3301.304476717189 - 21 -1245.809053745033 - 0 -SOLID - 5 -3A1 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3301.124476717212 - 20 -1245.809053745033 - 30 -0 - 11 -3301.304476717212 - 21 -1245.839026240393 - 31 -0 - 12 -3301.304476717212 - 22 -1245.779081249673 - 32 -0 - 13 -3301.304476717212 - 23 -1245.779081249673 - 33 -0 - 0 -SOLID - 5 -3A2 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3302.324476717166 - 20 -1245.809053745033 - 30 -0 - 11 -3302.144476717166 - 21 -1245.779081249673 - 31 -0 - 12 -3302.144476717166 - 22 -1245.839026240393 - 32 -0 - 13 -3302.144476717166 - 23 -1245.839026240393 - 33 -0 - 0 -LINE - 5 -3A3 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3302.144476717189 - 20 -1245.809053745033 - 11 -3302.324476717166 - 21 -1245.809053745033 - 0 -MTEXT - 5 -3A4 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3301.724476717189 - 20 -1245.809053745033 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3A5 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3301.124476717212 - 20 -1245.652369962656 - 11 -3301.124476717212 - 21 -1245.989053745033 - 0 -LINE - 5 -3A6 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3302.324476717166 - 20 -1245.652369962656 - 11 -3302.324476717166 - 21 -1245.989053745033 - 0 -ENDBLK - 5 -17A -330 -178 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -17C -330 -17B -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D29 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D29 - 1 - - 0 -LINE - 5 -3A7 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3281.603068378181 - 20 -1243.756682050024 - 11 -3281.783068378211 - 21 -1243.756682050024 - 0 -SOLID - 5 -3A8 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3281.603068378181 - 20 -1243.756682050024 - 30 -0 - 11 -3281.783068378181 - 21 -1243.786654545384 - 31 -0 - 12 -3281.783068378181 - 22 -1243.726709554664 - 32 -0 - 13 -3281.783068378181 - 23 -1243.726709554664 - 33 -0 - 0 -SOLID - 5 -3A9 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3282.803068378242 - 20 -1243.756682050024 - 30 -0 - 11 -3282.623068378242 - 21 -1243.726709554664 - 31 -0 - 12 -3282.623068378242 - 22 -1243.786654545384 - 32 -0 - 13 -3282.623068378242 - 23 -1243.786654545384 - 33 -0 - 0 -LINE - 5 -3AA -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3282.623068378212 - 20 -1243.756682050024 - 11 -3282.803068378242 - 21 -1243.756682050024 - 0 -MTEXT - 5 -3AB -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3282.203068378212 - 20 -1243.756682050024 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3AC -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3281.603068378181 - 20 -1245.952369962646 - 11 -3281.603068378181 - 21 -1243.576682050024 - 0 -LINE - 5 -3AD -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3282.803068378242 - 20 -1243.552370008162 - 11 -3282.803068378242 - 21 -1243.936682050024 - 0 -ENDBLK - 5 -17D -330 -17B -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -17F -330 -17E -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D21 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D21 - 1 - - 0 -LINE - 5 -3AE -100 -AcDbEntity - 8 -BLK_1_MAX_HEIGHT_CAL - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3701.825734416305 - 20 -1113.585719006579 - 11 -3703.251184360891 - 21 -1105.062257586579 - 0 -SOLID - 5 -3AF -100 -AcDbEntity - 8 -BLK_1_MAX_HEIGHT_CAL - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3701.825734416305 - 20 -1113.585719006579 - 30 -0 - 11 -3701.884986928338 - 21 -1113.413128478751 - 31 -0 - 12 -3701.825863044339 - 22 -1113.403240695723 - 32 -0 - 13 -3701.825863044339 - 23 -1113.403240695723 - 33 -0 - 0 -SOLID - 5 -3B0 -100 -AcDbEntity - 8 -BLK_1_MAX_HEIGHT_CAL - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3704.73684012501 - 20 -1096.178796166579 - 30 -0 - 11 -3704.677587612978 - 21 -1096.351386694407 - 31 -0 - 12 -3704.736711496977 - 22 -1096.361274477435 - 32 -0 - 13 -3704.736711496977 - 23 -1096.361274477435 - 33 -0 - 0 -LINE - 5 -3B1 -100 -AcDbEntity - 8 -BLK_1_MAX_HEIGHT_CAL - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3703.311390180424 - 20 -1104.702257586579 - 11 -3704.73684012501 - 21 -1096.178796166579 - 0 -MTEXT - 5 -3B2 -100 -AcDbEntity - 8 -BLK_1_MAX_HEIGHT_CAL - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3703.281287270659 - 20 -1104.882257586579 - 30 -0 - 40 -0.18 - 41 -0.8200000000000112 - 71 - 5 - 72 - 1 - 1 -17.6487 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3B3 -100 -AcDbEntity - 8 -BLK_1_MAX_HEIGHT_CAL - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3702.961422993541 - 20 -1113.775649733043 - 11 -3701.648199996963 - 21 -1113.556028436546 - 0 -LINE - 5 -3B4 -100 -AcDbEntity - 8 -BLK_1_MAX_HEIGHT_CAL - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3705.551110057835 - 20 -1096.31497335721 - 11 -3704.559305705668 - 21 -1096.149105596546 - 0 -ENDBLK - 5 -180 -330 -17E -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -182 -330 -181 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D37 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D37 - 1 - - 0 -LINE - 5 -3B5 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.977986036755 - 20 -1243.079906268309 - 11 -3317.077986036848 - 21 -1243.079906268309 - 0 -SOLID - 5 -3B6 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.977986036755 - 20 -1243.079906268309 - 30 -0 - 11 -3317.797986036755 - 21 -1243.049933772949 - 31 -0 - 12 -3317.797986036755 - 22 -1243.109878763669 - 32 -0 - 13 -3317.797986036755 - 23 -1243.109878763669 - 33 -0 - 0 -SOLID - 5 -3B7 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.077986036848 - 20 -1243.079906268309 - 30 -0 - 11 -3317.257986036848 - 21 -1243.109878763669 - 31 -0 - 12 -3317.257986036848 - 22 -1243.049933772949 - 32 -0 - 13 -3317.257986036848 - 23 -1243.049933772949 - 33 -0 - 0 -MTEXT - 5 -3B8 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3316.43466407232 - 20 -1243.079906268309 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -0.9000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3B9 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.977986036755 - 20 -1243.157187089064 - 11 -3317.977986036755 - 21 -1242.899906268309 - 0 -LINE - 5 -3BA -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.077986036848 - 20 -1243.157187089064 - 11 -3317.077986036848 - 21 -1242.899906268309 - 0 -ENDBLK - 5 -183 -330 -181 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -185 -330 -184 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D32 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D32 - 1 - - 0 -LINE - 5 -3BB -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.810469436013 - 20 -1243.552369962674 - 11 -3299.810469436013 - 21 -1245.472369962653 - 0 -SOLID - 5 -3BC -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.810469436013 - 20 -1243.552369962674 - 30 -0 - 11 -3299.780496940653 - 21 -1243.732369962674 - 31 -0 - 12 -3299.840441931373 - 22 -1243.732369962674 - 32 -0 - 13 -3299.840441931373 - 23 -1243.732369962674 - 33 -0 - 0 -SOLID - 5 -3BD -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.810469436013 - 20 -1247.752369962632 - 30 -0 - 11 -3299.840441931373 - 21 -1247.572369962632 - 31 -0 - 12 -3299.780496940653 - 22 -1247.572369962632 - 32 -0 - 13 -3299.780496940653 - 23 -1247.572369962632 - 33 -0 - 0 -LINE - 5 -3BE -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.810469436013 - 20 -1245.832369962653 - 11 -3299.810469436013 - 21 -1247.752369962632 - 0 -MTEXT - 5 -3BF -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3299.810469436013 - 20 -1245.652369962653 - 30 -0 - 40 -0.18 - 41 -0.72 - 71 - 5 - 72 - 1 - 1 -4.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3C0 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.81046943599 - 20 -1243.552369962674 - 11 -3299.630469436013 - 21 -1243.552369962674 - 0 -LINE - 5 -3C1 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.810469435998 - 20 -1247.752369962632 - 11 -3299.630469436013 - 21 -1247.752369962632 - 0 -ENDBLK - 5 -186 -330 -184 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -188 -330 -187 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D78 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D78 - 1 - - 0 -LINE - 5 -3C2 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369127 - 20 -1252.686624971338 - 11 -3427.522237369128 - 21 -1254.306622577448 - 0 -SOLID - 5 -3C3 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.522237369127 - 20 -1252.686624971338 - 30 -0 - 11 -3427.492264873767 - 21 -1252.866624971338 - 31 -0 - 12 -3427.552209864487 - 22 -1252.866624971338 - 32 -0 - 13 -3427.552209864487 - 23 -1252.866624971338 - 33 -0 - 0 -SOLID - 5 -3C4 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.522237369127 - 20 -1256.28662018356 - 30 -0 - 11 -3427.552209864487 - 21 -1256.10662018356 - 31 -0 - 12 -3427.492264873767 - 22 -1256.10662018356 - 32 -0 - 13 -3427.492264873767 - 23 -1256.10662018356 - 33 -0 - 0 -LINE - 5 -3C5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369128 - 20 -1254.666622577448 - 11 -3427.522237369127 - 21 -1256.28662018356 - 0 -MTEXT - 5 -3C6 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3427.394713937259 - 20 -1254.486622577448 - 30 -0 - 40 -0.18 - 41 -0.7000000000000224 - 71 - 5 - 72 - 1 - 1 -3.6000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3C7 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.994593221261 - 20 -1252.686624971338 - 11 -3427.342237369127 - 21 -1252.686624971338 - 0 -LINE - 5 -3C8 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369125 - 20 -1256.28662018356 - 11 -3427.342237369127 - 21 -1256.28662018356 - 0 -ENDBLK - 5 -189 -330 -187 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -18B -330 -18A -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D25 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D25 - 1 - - 0 -LINE - 5 -3C9 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.703068392752 - 20 -1243.079906270055 - 11 -3282.803068392845 - 21 -1243.079906270055 - 0 -SOLID - 5 -3CA -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3283.703068392752 - 20 -1243.079906270055 - 30 -0 - 11 -3283.523068392752 - 21 -1243.049933774695 - 31 -0 - 12 -3283.523068392752 - 22 -1243.109878765415 - 32 -0 - 13 -3283.523068392752 - 23 -1243.109878765415 - 33 -0 - 0 -SOLID - 5 -3CB -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3282.803068392845 - 20 -1243.079906270055 - 30 -0 - 11 -3282.983068392845 - 21 -1243.109878765415 - 31 -0 - 12 -3282.983068392845 - 22 -1243.049933774695 - 32 -0 - 13 -3282.983068392845 - 23 -1243.049933774695 - 33 -0 - 0 -MTEXT - 5 -3CC -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3282.159746428316 - 20 -1243.079906270055 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -0.9000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3CD -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.703068392752 - 20 -1243.15718709081 - 11 -3283.703068392752 - 21 -1242.899906270055 - 0 -LINE - 5 -3CE -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3282.803068392845 - 20 -1243.15718709081 - 11 -3282.803068392845 - 21 -1242.899906270055 - 0 -ENDBLK - 5 -18C -330 -18A -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -18E -330 -18D -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D14 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D14 - 1 - - 0 -LINE - 5 -3CF -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3707.563574271881 - 20 -1108.933105405074 - 11 -3707.633024817817 - 21 -1108.517826670716 - 0 -SOLID - 5 -3D0 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3707.563574271881 - 20 -1108.933105405074 - 30 -0 - 11 -3707.622826783913 - 21 -1108.760514877246 - 31 -0 - 12 -3707.563702899914 - 22 -1108.750627094218 - 32 -0 - 13 -3707.563702899914 - 23 -1108.750627094218 - 33 -0 - 0 -SOLID - 5 -3D1 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3707.769716797048 - 20 -1107.700478565417 - 30 -0 - 11 -3707.710464285016 - 21 -1107.873069093245 - 31 -0 - 12 -3707.769588169015 - 22 -1107.882956876274 - 32 -0 - 13 -3707.769588169015 - 23 -1107.882956876274 - 33 -0 - 0 -LINE - 5 -3D2 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3707.693230637351 - 20 -1108.157826670716 - 11 -3707.769716797048 - 21 -1107.700478565417 - 0 -MTEXT - 5 -3D3 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3707.792422192403 - 20 -1108.337826670716 - 30 -0 - 40 -0.18 - 41 -0.68 - 71 - 5 - 72 - 1 - 1 -1.2497 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3D4 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3707.650442678567 - 20 -1108.947633137341 - 11 -3707.386039852539 - 21 -1108.903414835042 - 0 -LINE - 5 -3D5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3707.882337505863 - 20 -1107.719313071169 - 11 -3707.592182377706 - 21 -1107.670787995385 - 0 -ENDBLK - 5 -18F -330 -18D -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -191 -330 -190 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D85 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D85 - 1 - - 0 -LINE - 5 -3D6 -100 -AcDbEntity - 8 -BLK_1_FLR_2_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3440.165820340022 - 20 -1259.886620183188 - 11 -3440.165820340022 - 21 -1258.266620183374 - 0 -SOLID - 5 -3D7 -100 -AcDbEntity - 8 -BLK_1_FLR_2_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3440.165820340022 - 20 -1259.886620183188 - 30 -0 - 11 -3440.195792835382 - 21 -1259.706620183188 - 31 -0 - 12 -3440.135847844662 - 22 -1259.706620183188 - 32 -0 - 13 -3440.135847844662 - 23 -1259.706620183188 - 33 -0 - 0 -SOLID - 5 -3D8 -100 -AcDbEntity - 8 -BLK_1_FLR_2_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3440.165820340022 - 20 -1256.28662018356 - 30 -0 - 11 -3440.135847844662 - 21 -1256.46662018356 - 31 -0 - 12 -3440.195792835382 - 22 -1256.46662018356 - 32 -0 - 13 -3440.195792835382 - 23 -1256.46662018356 - 33 -0 - 0 -LINE - 5 -3D9 -100 -AcDbEntity - 8 -BLK_1_FLR_2_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3440.165820340022 - 20 -1257.906620183374 - 11 -3440.165820340022 - 21 -1256.28662018356 - 0 -MTEXT - 5 -3DA -100 -AcDbEntity - 8 -BLK_1_FLR_2_HT_ROOM - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3440.165820340022 - 20 -1258.086620183374 - 30 -0 - 40 -0.18 - 41 -0.7000000000000224 - 71 - 5 - 72 - 1 - 1 -3.6000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3DB -100 -AcDbEntity - 8 -BLK_1_FLR_2_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3440.149415793408 - 20 -1259.886620183188 - 11 -3440.345820340022 - 21 -1259.886620183188 - 0 -LINE - 5 -3DC -100 -AcDbEntity - 8 -BLK_1_FLR_2_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3440.149415793408 - 20 -1256.28662018356 - 11 -3440.345820340022 - 21 -1256.28662018356 - 0 -ENDBLK - 5 -192 -330 -190 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -194 -330 -193 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D76 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D76 - 1 - - 0 -LINE - 5 -3DD -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.69992944449 - 20 -1246.986620183514 - 11 -3427.342237369113 - 21 -1246.986620183514 - 0 -LINE - 5 -3DE -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.69992944449 - 20 -1248.636620183537 - 11 -3427.342237369113 - 21 -1248.636620183537 - 0 -LINE - 5 -3DF -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369113 - 20 -1246.986620183514 - 11 -3427.522237369113 - 21 -1247.631620183526 - 0 -SOLID - 5 -3E0 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.522237369113 - 20 -1246.986620183514 - 30 -0 - 11 -3427.492264873753 - 21 -1247.166620183514 - 31 -0 - 12 -3427.552209864473 - 22 -1247.166620183514 - 32 -0 - 13 -3427.552209864473 - 23 -1247.166620183514 - 33 -0 - 0 -SOLID - 5 -3E1 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.522237369113 - 20 -1248.636620183537 - 30 -0 - 11 -3427.552209864473 - 21 -1248.456620183537 - 31 -0 - 12 -3427.492264873753 - 22 -1248.456620183537 - 32 -0 - 13 -3427.492264873753 - 23 -1248.456620183537 - 33 -0 - 0 -LINE - 5 -3E2 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369113 - 20 -1247.991620183526 - 11 -3427.522237369113 - 21 -1248.636620183537 - 0 -MTEXT - 5 -3E3 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3427.394713937245 - 20 -1247.811620183526 - 30 -0 - 40 -0.18 - 41 -0.6600000000000223 - 71 - 5 - 72 - 1 - 1 -1.6500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -195 -330 -193 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -197 -330 -196 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D15 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D15 - 1 - - 0 -LINE - 5 -3E4 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3707.685515145951 - 20 -1107.686396817056 - 11 -3707.751080364225 - 21 -1107.294350354412 - 0 -SOLID - 5 -3E5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3707.685515145951 - 20 -1107.686396817056 - 30 -0 - 11 -3707.744767657984 - 21 -1107.513806289228 - 31 -0 - 12 -3707.685643773985 - 22 -1107.5039185062 - 32 -0 - 13 -3707.685643773985 - 23 -1107.5039185062 - 33 -0 - 0 -SOLID - 5 -3E6 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3707.883887015795 - 20 -1106.500234520827 - 30 -0 - 11 -3707.824634503763 - 21 -1106.672825048655 - 31 -0 - 12 -3707.883758387762 - 22 -1106.682712831683 - 32 -0 - 13 -3707.883758387762 - 23 -1106.682712831683 - 33 -0 - 0 -LINE - 5 -3E7 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3707.811286183759 - 20 -1106.934350354412 - 11 -3707.883887015795 - 21 -1106.500234520827 - 0 -MTEXT - 5 -3E8 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3707.910477738811 - 20 -1107.114350354412 - 30 -0 - 40 -0.18 - 41 -0.6600000000000112 - 71 - 5 - 72 - 1 - 1 -1.2026 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3E9 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3707.764369543838 - 20 -1107.699584299413 - 11 -3707.507980726609 - 21 -1107.656706247023 - 0 -LINE - 5 -3EA -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3707.997366203883 - 20 -1106.519212597268 - 11 -3707.706352596453 - 21 -1106.470543950794 - 0 -ENDBLK - 5 -198 -330 -196 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -19A -330 -199 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D9 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D9 - 1 - - 0 -LINE - 5 -3EB -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3698.04843085989 - 20 -1107.017542090556 - 11 -3698.150796985409 - 21 -1106.490908174588 - 0 -LINE - 5 -3EC -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3711.16218060348 - 20 -1109.566568485509 - 11 -3711.264546728999 - 21 -1109.039934569541 - 0 -LINE - 5 -3ED -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3698.116451734113 - 20 -1106.667601139115 - 11 -3704.391301684291 - 21 -1107.887294854499 - 0 -SOLID - 5 -3EE -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3698.116451734113 - 20 -1106.667601139115 - 30 -0 - 11 -3698.287425738167 - 21 -1106.731368218519 - 31 -0 - 12 -3698.298863659113 - 22 -1106.672524562304 - 32 -0 - 13 -3698.298863659113 - 23 -1106.672524562304 - 33 -0 - 0 -SOLID - 5 -3EF -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3711.230201477702 - 20 -1109.216627534068 - 30 -0 - 11 -3711.059227473648 - 21 -1109.152860454664 - 31 -0 - 12 -3711.047789552702 - 22 -1109.211704110879 - 32 -0 - 13 -3711.047789552702 - 23 -1109.211704110879 - 33 -0 - 0 -LINE - 5 -3F0 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3705.138994248611 - 20 -1108.032629950793 - 11 -3711.230201477702 - 21 -1109.216627534068 - 0 -MTEXT - 5 -3F1 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3704.648994248611 - 20 -1108.067294854499 - 30 -0 - 40 -0.18 - 41 -0.8000000000000336 - 71 - 5 - 72 - 1 - 1 -13.3592 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -19B -330 -199 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -19D -330 -19C -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D51 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D51 - 1 - - 0 -LINE - 5 -3F2 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.838675251231 - 20 -1258.458460622718 - 11 -3352.088675251034 - 21 -1258.458460622718 - 0 -SOLID - 5 -3F3 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3352.838675251231 - 20 -1258.458460622718 - 30 -0 - 11 -3352.658675251231 - 21 -1258.428488127358 - 31 -0 - 12 -3352.658675251231 - 22 -1258.488433118078 - 32 -0 - 13 -3352.658675251231 - 23 -1258.488433118078 - 33 -0 - 0 -SOLID - 5 -3F4 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3352.088675251034 - 20 -1258.458460622718 - 30 -0 - 11 -3352.268675251034 - 21 -1258.488433118078 - 31 -0 - 12 -3352.268675251034 - 22 -1258.428488127358 - 32 -0 - 13 -3352.268675251034 - 23 -1258.428488127358 - 33 -0 - 0 -MTEXT - 5 -3F5 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3351.445353286505 - 20 -1258.458460622718 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3F6 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.838675251231 - 20 -1258.300104121969 - 11 -3352.838675251231 - 21 -1258.638460622718 - 0 -LINE - 5 -3F7 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.088675251034 - 20 -1258.300104121969 - 11 -3352.088675251034 - 21 -1258.638460622718 - 0 -ENDBLK - 5 -19E -330 -19C -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1A0 -330 -19F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D41 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D41 - 1 - - 0 -LINE - 5 -3F8 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3315.877986022184 - 20 -1243.756683315703 - 11 -3316.057986022213 - 21 -1243.756683315703 - 0 -SOLID - 5 -3F9 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3315.877986022184 - 20 -1243.756683315703 - 30 -0 - 11 -3316.057986022184 - 21 -1243.786655811063 - 31 -0 - 12 -3316.057986022184 - 22 -1243.726710820343 - 32 -0 - 13 -3316.057986022184 - 23 -1243.726710820343 - 33 -0 - 0 -SOLID - 5 -3FA -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.077986022245 - 20 -1243.756683315703 - 30 -0 - 11 -3316.897986022245 - 21 -1243.726710820343 - 31 -0 - 12 -3316.897986022245 - 22 -1243.786655811063 - 32 -0 - 13 -3316.897986022245 - 23 -1243.786655811063 - 33 -0 - 0 -LINE - 5 -3FB -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.897986022214 - 20 -1243.756683315703 - 11 -3317.077986022245 - 21 -1243.756683315703 - 0 -MTEXT - 5 -3FC -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3316.477986022214 - 20 -1243.756683315703 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3FD -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3315.877986022184 - 20 -1245.9523699609 - 11 -3315.877986022184 - 21 -1243.576683315703 - 0 -LINE - 5 -3FE -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.077986022245 - 20 -1243.552371273841 - 11 -3317.077986022245 - 21 -1243.936683315703 - 0 -ENDBLK - 5 -1A1 -330 -19F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1A3 -330 -1A2 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D68 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D68 - 1 - - 0 -LINE - 5 -3FF -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.977986019338 - 20 -1245.414869962667 - 11 -3317.977986019338 - 21 -1246.400390913326 - 0 -LINE - 5 -400 -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3319.177986019524 - 20 -1245.414869962667 - 11 -3319.177986019524 - 21 -1246.400390913326 - 0 -LINE - 5 -401 -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.977986019338 - 20 -1246.220390913326 - 11 -3318.157986019431 - 21 -1246.220390913326 - 0 -SOLID - 5 -402 -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.977986019338 - 20 -1246.220390913326 - 30 -0 - 11 -3318.157986019338 - 21 -1246.250363408686 - 31 -0 - 12 -3318.157986019338 - 22 -1246.190418417966 - 32 -0 - 13 -3318.157986019338 - 23 -1246.190418417966 - 33 -0 - 0 -SOLID - 5 -403 -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3319.177986019524 - 20 -1246.220390913326 - 30 -0 - 11 -3318.997986019524 - 21 -1246.190418417966 - 31 -0 - 12 -3318.997986019524 - 22 -1246.250363408686 - 32 -0 - 13 -3318.997986019524 - 23 -1246.250363408686 - 33 -0 - 0 -LINE - 5 -404 -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3318.997986019431 - 20 -1246.220390913326 - 11 -3319.177986019524 - 21 -1246.220390913326 - 0 -MTEXT - 5 -405 -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3318.577986019431 - 20 -1246.220390913326 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -1A4 -330 -1A2 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1A6 -330 -1A5 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D45 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D45 - 1 - - 0 -LINE - 5 -406 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3354.188675249481 - 20 -1245.809053745032 - 11 -3354.368675249458 - 21 -1245.809053745032 - 0 -SOLID - 5 -407 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3354.188675249481 - 20 -1245.809053745032 - 30 -0 - 11 -3354.368675249481 - 21 -1245.839026240392 - 31 -0 - 12 -3354.368675249481 - 22 -1245.779081249672 - 32 -0 - 13 -3354.368675249481 - 23 -1245.779081249672 - 33 -0 - 0 -SOLID - 5 -408 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3355.388675249435 - 20 -1245.809053745032 - 30 -0 - 11 -3355.208675249435 - 21 -1245.779081249672 - 31 -0 - 12 -3355.208675249435 - 22 -1245.839026240392 - 32 -0 - 13 -3355.208675249435 - 23 -1245.839026240392 - 33 -0 - 0 -LINE - 5 -409 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3355.208675249458 - 20 -1245.809053745032 - 11 -3355.388675249435 - 21 -1245.809053745032 - 0 -MTEXT - 5 -40A -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3354.788675249458 - 20 -1245.809053745032 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -40B -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3354.188675249481 - 20 -1245.652369962656 - 11 -3354.188675249481 - 21 -1245.989053745032 - 0 -LINE - 5 -40C -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3355.388675249435 - 20 -1245.652369962656 - 11 -3355.388675249435 - 21 -1245.989053745032 - 0 -ENDBLK - 5 -1A7 -330 -1A5 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1A9 -330 -1A8 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D40 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D40 - 1 - - 0 -LINE - 5 -40D -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.527986022219 - 20 -1243.552369960933 - 11 -3317.527986022219 - 21 -1243.13236941446 - 0 -SOLID - 5 -40E -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.527986022219 - 20 -1243.552369960933 - 30 -0 - 11 -3317.557958517579 - 21 -1243.372369960933 - 31 -0 - 12 -3317.498013526859 - 22 -1243.372369960933 - 32 -0 - 13 -3317.498013526859 - 23 -1243.372369960933 - 33 -0 - 0 -SOLID - 5 -40F -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.527986022219 - 20 -1242.352368867987 - 30 -0 - 11 -3317.498013526859 - 21 -1242.532368867987 - 31 -0 - 12 -3317.557958517579 - 22 -1242.532368867987 - 32 -0 - 13 -3317.557958517579 - 23 -1242.532368867987 - 33 -0 - 0 -LINE - 5 -410 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.527986022219 - 20 -1242.77236941446 - 11 -3317.527986022219 - 21 -1242.352368867987 - 0 -MTEXT - 5 -411 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3317.527986022219 - 20 -1242.95236941446 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -412 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.527986022199 - 20 -1243.552369960933 - 11 -3317.707986022219 - 21 -1243.552369960933 - 0 -LINE - 5 -413 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.5272526697 - 20 -1242.352368867987 - 11 -3317.707986022219 - 21 -1242.352368867987 - 0 -ENDBLK - 5 -1AA -330 -1A8 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1AC -330 -1AB -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -_ArchTick - 70 - 0 - 10 -0 - 20 -0 - 3 -_ArchTick - 1 - - 0 -LWPOLYLINE - 5 -414 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 --0.5 - 20 --0.5 - 10 -0.5 - 20 -0.5 - 0 -ENDBLK - 5 -1AD -330 -1AB -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1AF -330 -1AE -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -15 - 70 - 0 - 10 -0 - 20 -0 - 3 -15 - 1 - - 0 -ARC - 5 -415 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --734091.4099779375 - 20 -80100.94134111518 - 40 -70.32638888976521 -100 -AcDbArc - 50 -91.56964921010622 - 51 -180 - 0 -ARC - 5 -416 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --734165.2626789922 - 20 -80096.93645957157 - 40 -5.257852012237923 -100 -AcDbArc - 50 -2.233197218398334 - 51 -71.98227889500916 - 0 -LINE - 5 -417 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734163.6363668273 - 20 -80102.84134111532 - 11 --734163.6363668273 - 21 -80097.14134111512 - 0 -ARC - 5 -418 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --734167.1882080254 - 20 -80096.54173647799 - 40 -5.257852012237923 -100 -AcDbArc - 50 -6.548247974590567 - 51 -47.50461327031654 - 0 -LWPOLYLINE - 5 -419 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbPolyline - 90 - 31 - 70 - 0 - 43 -0 - 10 --734163.6363668273 - 20 -80097.14134111512 - 10 --734163.6363668273 - 20 -80097.14134111512 - 10 --734163.1723273654 - 20 -80097.44901241222 - 10 --734162.7565162109 - 20 -80097.71946787395 - 10 --734162.3857100526 - 20 -80097.95577616198 - 10 --734162.056685581 - 20 -80098.16100593797 - 10 --734161.7662194849 - 20 -80098.33822586434 - 10 --734161.5110884544 - 20 -80098.4905046036 - 10 --734161.2880691785 - 20 -80098.62091081683 - 10 --734161.0939383473 - 20 -80098.73251316648 - 10 --734160.9255309461 - 20 -80098.82822946853 - 10 --734160.7799151447 - 20 -80098.91037415131 - 10 --734160.6542174083 - 20 -80098.98111079843 - 10 --734160.5455642029 - 20 -80099.04260299215 - 10 --734160.4510819934 - 20 -80099.09701431516 - 10 --734160.3678972463 - 20 -80099.14650835002 - 10 --734160.2931364268 - 20 -80099.19324867986 - 10 --734160.2239260002 - 20 -80099.23939888713 - 10 --734160.1580001159 - 20 -80099.28655706812 - 10 --734160.0955236605 - 20 -80099.33405937278 - 10 --734160.0372692031 - 20 -80099.38067646488 - 10 --734159.9840093135 - 20 -80099.42517900723 - 10 --734159.9365165612 - 20 -80099.46633766427 - 10 --734159.8955635166 - 20 -80099.50292309909 - 10 --734159.8619227484 - 20 -80099.5337059747 - 10 --734159.8363668271 - 20 -80099.55745695531 - 10 --734162.3317586886 - 20 -80098.01414672192 - 10 --734160.8201769179 - 20 -80098.90035531577 - 10 --734160.1953728407 - 20 -80099.22261531162 - 10 --734159.8930494264 - 20 -80099.5045896107 - 10 --734159.8363668271 - 20 -80099.55745695531 - 0 -LWPOLYLINE - 5 -41A -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbPolyline - 90 - 31 - 70 - 0 - 43 -0 - 10 --734163.6015240891 - 20 -80097.1883538838 - 10 --734163.6015240891 - 20 -80097.1883538838 - 10 --734163.3875578792 - 20 -80097.60942625767 - 10 --734163.2105751225 - 20 -80097.97194359101 - 10 --734163.0650450413 - 20 -80098.28438336543 - 10 --734162.9454368583 - 20 -80098.5552230624 - 10 --734162.8462197967 - 20 -80098.79294016329 - 10 --734162.7618630792 - 20 -80099.00601214916 - 10 --734162.6868359284 - 20 -80099.20291650177 - 10 --734162.6156075672 - 20 -80099.39213070294 - 10 --734162.5437002353 - 20 -80099.58080452634 - 10 --734162.4708482389 - 20 -80099.77077691932 - 10 --734162.397838902 - 20 -80099.96255912072 - 10 --734162.3254595482 - 20 -80100.15666237148 - 10 --734162.2544975006 - 20 -80100.35359790991 - 10 --734162.1857400835 - 20 -80100.55387697672 - 10 --734162.1199746196 - 20 -80100.75801081119 - 10 --734162.0579884327 - 20 -80100.9665106528 - 10 --734162.0004589543 - 20 -80101.17905548959 - 10 --734161.9476240454 - 20 -80101.39199530031 - 10 --734161.8996116756 - 20 -80101.60084781237 - 10 --734161.8565498136 - 20 -80101.80113075326 - 10 --734161.8185664287 - 20 -80101.98836184946 - 10 --734161.78578949 - 20 -80102.15805882867 - 10 --734161.7583469664 - 20 -80102.3057394179 - 10 --734161.7363668274 - 20 -80102.4269213439 - 10 --734162.9767200124 - 20 -80098.39682247373 - 10 --734162.6340821024 - 20 -80099.38373252051 - 10 --734162.0092780259 - 20 -80100.91448668436 - 10 --734161.7875836025 - 20 -80102.14308533377 - 10 --734161.7363668274 - 20 -80102.4269213439 - 0 -LINE - 5 -41B -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734159.8363668271 - 20 -80097.14134111512 - 11 --734159.8363668271 - 21 -80100.94134111518 - 0 -LINE - 5 -41C -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734163.6363668273 - 20 -80097.14134111512 - 11 --734159.8363668271 - 21 -80097.14134111512 - 0 -LINE - 5 -41D -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734161.7363668274 - 20 -80102.84134111532 - 11 --734163.6363668273 - 21 -80102.84134111532 - 0 -LINE - 5 -41E -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734161.7363668274 - 20 -80100.94134111518 - 11 --734161.7363668274 - 21 -80102.84134111532 - 0 -LINE - 5 -41F -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734159.8363668271 - 20 -80100.94134111518 - 11 --734161.7363668274 - 21 -80100.94134111518 - 0 -LINE - 5 -420 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734091.4363668264 - 20 -80102.84134111532 - 11 --734091.4363668264 - 21 -80171.24134111615 - 0 -LINE - 5 -421 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734089.5363668264 - 20 -80100.94134111518 - 11 --734089.5363668264 - 21 -80171.24134111615 - 0 -LINE - 5 -422 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734087.6363668264 - 20 -80102.84134111532 - 11 --734087.6363668264 - 21 -80097.14134111512 - 0 -ARC - 5 -423 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --734084.084525628 - 20 -80096.54173647799 - 40 -5.257852012237923 -100 -AcDbArc - 50 -132.4953867296834 - 51 -173.4517520254094 - 0 -ARC - 5 -424 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --734086.0100546615 - 20 -80096.93645957157 - 40 -5.257852012237923 -100 -AcDbArc - 50 -108.0177211049908 - 51 -177.7668027816016 - 0 -LWPOLYLINE - 5 -425 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbPolyline - 90 - 31 - 70 - 0 - 43 -0 - 10 --734087.6363668264 - 20 -80097.14134111512 - 10 --734087.6363668264 - 20 -80097.14134111512 - 10 --734088.1004062882 - 20 -80097.44901241222 - 10 --734088.5162174429 - 20 -80097.71946787395 - 10 --734088.887023601 - 20 -80097.95577616198 - 10 --734089.2160480727 - 20 -80098.16100593797 - 10 --734089.506514169 - 20 -80098.33822586459 - 10 --734089.7616451994 - 20 -80098.4905046036 - 10 --734089.9846644752 - 20 -80098.62091081683 - 10 --734090.1787953064 - 20 -80098.73251316648 - 10 --734090.3472027074 - 20 -80098.82822946853 - 10 --734090.4928185089 - 20 -80098.91037415131 - 10 --734090.6185162457 - 20 -80098.98111079843 - 10 --734090.727169451 - 20 -80099.04260299215 - 10 --734090.8216516601 - 20 -80099.09701431516 - 10 --734090.9048364074 - 20 -80099.14650835002 - 10 --734090.9795972272 - 20 -80099.19324867986 - 10 --734091.0488076537 - 20 -80099.23939888713 - 10 --734091.1147335377 - 20 -80099.28655706812 - 10 --734091.1772099932 - 20 -80099.33405937278 - 10 --734091.2354644507 - 20 -80099.38067646488 - 10 --734091.2887243401 - 20 -80099.42517900723 - 10 --734091.3362170924 - 20 -80099.46633766427 - 10 --734091.3771701372 - 20 -80099.50292309909 - 10 --734091.4108109052 - 20 -80099.5337059747 - 10 --734091.4363668264 - 20 -80099.55745695531 - 10 --734088.9409749656 - 20 -80098.01414672192 - 10 --734090.4525567363 - 20 -80098.90035531577 - 10 --734091.0773608128 - 20 -80099.22261531182 - 10 --734091.3796842272 - 20 -80099.5045896107 - 10 --734091.4363668264 - 20 -80099.55745695531 - 0 -LWPOLYLINE - 5 -426 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbPolyline - 90 - 31 - 70 - 0 - 43 -0 - 10 --734087.6712095645 - 20 -80097.1883538838 - 10 --734087.6712095645 - 20 -80097.1883538838 - 10 --734087.8851757747 - 20 -80097.60942625767 - 10 --734088.0621585316 - 20 -80097.97194359101 - 10 --734088.2076886126 - 20 -80098.28438336543 - 10 --734088.3272967953 - 20 -80098.5552230624 - 10 --734088.4265138567 - 20 -80098.79294016329 - 10 --734088.5108705745 - 20 -80099.00601214916 - 10 --734088.5858977252 - 20 -80099.20291650177 - 10 --734088.6571260863 - 20 -80099.39213070294 - 10 --734088.7290334183 - 20 -80099.58080452634 - 10 --734088.8018854148 - 20 -80099.77077691932 - 10 --734088.8748947517 - 20 -80099.9625591212 - 10 --734088.9472741057 - 20 -80100.15666237148 - 10 --734089.0182361529 - 20 -80100.35359790991 - 10 --734089.0869935704 - 20 -80100.55387697672 - 10 --734089.1527590343 - 20 -80100.75801081119 - 10 --734089.214745221 - 20 -80100.9665106528 - 10 --734089.2722746994 - 20 -80101.17905548959 - 10 --734089.3251096081 - 20 -80101.39199530031 - 10 --734089.3731219782 - 20 -80101.60084781237 - 10 --734089.4161838399 - 20 -80101.80113075326 - 10 --734089.454167225 - 20 -80101.98836184946 - 10 --734089.4869441638 - 20 -80102.15805882867 - 10 --734089.5143866872 - 20 -80102.3057394179 - 10 --734089.5363668264 - 20 -80102.42692134411 - 10 --734088.2960136411 - 20 -80098.39682247373 - 10 --734088.6386515513 - 20 -80099.38373252051 - 10 --734089.263455628 - 20 -80100.91448668436 - 10 --734089.4851500515 - 20 -80102.14308533377 - 10 --734089.5363668264 - 20 -80102.42692134411 - 0 -LINE - 5 -427 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734091.4363668264 - 20 -80097.14134111512 - 11 --734091.4363668264 - 21 -80100.94134111518 - 0 -LINE - 5 -428 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734087.6363668264 - 20 -80097.14134111512 - 11 --734091.4363668264 - 21 -80097.14134111512 - 0 -LINE - 5 -429 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734091.4363668264 - 20 -80100.94134111518 - 11 --734089.5363668264 - 21 -80100.94134111518 - 0 -LINE - 5 -42A -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734087.6363668264 - 20 -80102.84134111532 - 11 --734091.4363668264 - 21 -80102.84134111532 - 0 -LINE - 5 -42B -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734091.4363668264 - 20 -80171.24134111615 - 11 --734089.5363668264 - 21 -80171.24134111615 - 0 -ENDBLK - 5 -1B0 -330 -1AE -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1B2 -330 -1B1 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -tre - 70 - 0 - 10 -0 - 20 -0 - 3 -tre - 1 - - 0 -LINE - 5 -42C -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255972.014028702 - 20 -16948.64158117022 - 11 -255971.1466769398 - 21 -16948.22025093948 - 0 -LINE - 5 -42D -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255900.8811767594 - 20 -16960.08043886342 - 11 -255900.8811767594 - 21 -16962.34541863444 - 0 -LINE - 5 -42E -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255900.8811767594 - 20 -16962.34541863444 - 11 -255901.0339511941 - 21 -16965.096771303 - 0 -LINE - 5 -42F -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255901.0339511941 - 20 -16965.096771303 - 11 -255901.7214405925 - 21 -16968.76524965129 - 0 -LINE - 5 -430 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255901.7214405925 - 20 -16968.76524965129 - 11 -255903.4019727012 - 21 -16971.44018178025 - 0 -LINE - 5 -431 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.4019727012 - 20 -16971.44018178025 - 11 -255905.464445339 - 21 -16974.49724707053 - 0 -LINE - 5 -432 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255905.464445339 - 20 -16974.49724707053 - 11 -255908.2907945926 - 21 -16976.25505961241 - 0 -LINE - 5 -433 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255908.2907945926 - 20 -16976.25505961241 - 11 -255912.3393482084 - 21 -16977.24859973907 - 0 -LINE - 5 -434 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255912.3393482084 - 20 -16977.24859973907 - 11 -255913.6379442306 - 21 -16977.55430626807 - 0 -LINE - 5 -435 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255913.6379442306 - 20 -16977.55430626807 - 11 -255914.4782080637 - 21 -16977.47787963581 - 0 -LINE - 5 -436 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255914.4782080637 - 20 -16977.47787963581 - 11 -255916.1587401722 - 21 -16976.17863298017 - 0 -LINE - 5 -437 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255916.1587401722 - 20 -16976.17863298017 - 11 -255917.3045573172 - 21 -16974.95580686404 - 0 -LINE - 5 -438 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255917.3045573172 - 20 -16974.95580686404 - 11 -255918.4503744621 - 21 -16972.35730136735 - 0 -LINE - 5 -439 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255918.4503744621 - 20 -16972.35730136735 - 11 -255919.2906427375 - 21 -16968.00098332872 - 0 -LINE - 5 -43A -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255919.2906427375 - 20 -16968.00098332872 - 11 -255919.6725832669 - 21 -16962.19256536994 - 0 -LINE - 5 -43B -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255919.6725832669 - 20 -16962.19256536994 - 11 -255919.8253577014 - 21 -16960.08043886342 - 0 -LINE - 5 -43C -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255919.8253577014 - 20 -16960.08043886342 - 11 -255919.6725832669 - 21 -16957.9683123569 - 0 -LINE - 5 -43D -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255919.6725832669 - 20 -16957.9683123569 - 11 -255919.2906427375 - 21 -16952.15989439811 - 0 -LINE - 5 -43E -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255919.2906427375 - 20 -16952.15989439811 - 11 -255918.4503744621 - 21 -16947.80357635949 - 0 -LINE - 5 -43F -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255918.4503744621 - 20 -16947.80357635949 - 11 -255917.3045573172 - 21 -16945.20507086277 - 0 -LINE - 5 -440 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255917.3045573172 - 20 -16945.20507086277 - 11 -255916.1587401722 - 21 -16943.98224474666 - 0 -LINE - 5 -441 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255916.1587401722 - 20 -16943.98224474666 - 11 -255914.4782080637 - 21 -16942.682998091 - 0 -LINE - 5 -442 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255914.4782080637 - 20 -16942.682998091 - 11 -255913.6379442306 - 21 -16942.60657145877 - 0 -LINE - 5 -443 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255913.6379442306 - 20 -16942.60657145877 - 11 -255912.3393482084 - 21 -16942.91227798777 - 0 -LINE - 5 -444 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255912.3393482084 - 20 -16942.91227798777 - 11 -255908.2907945926 - 21 -16943.9058181144 - 0 -LINE - 5 -445 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255908.2907945926 - 20 -16943.9058181144 - 11 -255905.464445339 - 21 -16945.66363065631 - 0 -LINE - 5 -446 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255905.464445339 - 20 -16945.66363065631 - 11 -255903.4019727012 - 21 -16948.72069594659 - 0 -LINE - 5 -447 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.4019727012 - 20 -16948.72069594659 - 11 -255901.7214405925 - 21 -16951.39562807554 - 0 -LINE - 5 -448 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255901.7214405925 - 20 -16951.39562807554 - 11 -255901.0339511941 - 21 -16955.06410642384 - 0 -LINE - 5 -449 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255901.0339511941 - 20 -16955.06410642384 - 11 -255900.8811767594 - 21 -16957.8154590924 - 0 -LINE - 5 -44A -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255900.8811767594 - 20 -16957.8154590924 - 11 -255900.8811767594 - 21 -16960.08043886342 - 0 -ARC - 5 -44B -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255916.3988343029 - 20 -16955.10161375379 - 40 -16.63276459285422 -100 -AcDbArc - 50 -212.9825838813756 - 51 -267.8609705026604 - 0 -LINE - 5 -44C -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255915.778025748 - 20 -16938.4804388634 - 11 -255916.316015082 - 21 -16938.75521048949 - 0 -ARC - 5 -44D -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255910.8578436243 - 20 -16949.44204184124 - 40 -12.00000000014797 -100 -AcDbArc - 50 -297.0551303575777 - 51 -313.545700673336 - 0 -LINE - 5 -44E -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255919.1250388443 - 20 -16940.74414076125 - 11 -255919.2579466097 - 21 -16940.87046715113 - 0 -LINE - 5 -44F -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255919.2579466097 - 20 -16940.87046715113 - 11 -255919.4799538744 - 21 -16941.14547200695 - 0 -ARC - 5 -450 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255910.1428005038 - 20 -16948.68321483453 - 40 -12.00000000002144 -100 -AcDbArc - 50 -321.0865864327741 - 51 -339.784627350406 - 0 -LINE - 5 -451 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255921.4036046356 - 20 -16944.53661498584 - 11 -255921.4174608355 - 21 -16944.57424387672 - 0 -ARC - 5 -452 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255910.1566567036 - 20 -16948.72084372542 - 40 -12.00000000001947 -100 -AcDbArc - 50 -339.784627350406 - 51 -347.4773250022013 - 0 -LINE - 5 -453 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255921.8711799912 - 20 -16946.11893209258 - 11 -255922.5595169441 - 21 -16949.21801476864 - 0 -ARC - 5 -454 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255910.8449936568 - 20 -16951.81992640147 - 40 -11.9999999998828 -100 -AcDbArc - 50 -347.4773250022013 - 51 -352.4091937246277 - 0 -LINE - 5 -455 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255922.7398346501 - 20 -16950.23475835329 - 11 -255923.2842283672 - 21 -16954.31979950199 - 0 -ARC - 5 -456 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255911.3893873738 - 20 -16955.90496754954 - 40 -11.99999999979925 -100 -AcDbArc - 50 -352.4091937279335 - 51 -358.4754835808301 - 0 -LINE - 5 -457 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255923.3851397643 - 20 -16955.58571125153 - 11 -255923.5047629486 - 21 -16960.08043886342 - 0 -LINE - 5 -458 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255914.4782080637 - 20 -16942.1480116652 - 11 -255915.547637991 - 21 -16939.16737300721 - 0 -ARC - 5 -459 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255916.3988343029 - 20 -16965.05926397305 - 40 -16.63276459285422 -100 -AcDbArc - 50 -92.13902949733965 - 51 -147.0174161186244 - 0 -LINE - 5 -45A -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255915.778025748 - 20 -16981.68043886342 - 11 -255916.316015082 - 21 -16981.40566723732 - 0 -ARC - 5 -45B -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255910.8578436243 - 20 -16970.7188358856 - 40 -12.00000000008443 -100 -AcDbArc - 50 -46.45429932695114 - 51 -62.94486964251714 - 0 -LINE - 5 -45C -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255919.1250388443 - 20 -16979.41673696558 - 11 -255919.2579466097 - 21 -16979.29041057571 - 0 -LINE - 5 -45D -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255919.2579466097 - 20 -16979.29041057571 - 11 -255919.4799538744 - 21 -16979.01540571989 - 0 -ARC - 5 -45E -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255910.1428005038 - 20 -16971.4776628923 - 40 -12.00000000002144 -100 -AcDbArc - 50 -20.21537264959403 - 51 -38.9134135672259 - 0 -LINE - 5 -45F -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255921.4036046356 - 20 -16975.624262741 - 11 -255921.4174608355 - 21 -16975.58663385011 - 0 -ARC - 5 -460 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255910.1566567036 - 20 -16971.44003400142 - 40 -12.00000000001947 -100 -AcDbArc - 50 -12.52267499779867 - 51 -20.21537264959403 - 0 -LINE - 5 -461 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255921.8711799912 - 20 -16974.04194563425 - 11 -255922.5595169441 - 21 -16970.9428629582 - 0 -ARC - 5 -462 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255910.8449936568 - 20 -16968.34095132536 - 40 -11.9999999998828 -100 -AcDbArc - 50 -7.590806275372302 - 51 -12.52267499779867 - 0 -LINE - 5 -463 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255922.7398346501 - 20 -16969.92611937355 - 11 -255923.2842283672 - 21 -16965.84107822484 - 0 -ARC - 5 -464 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255911.3893873738 - 20 -16964.2559101773 - 40 -11.99999999993772 -100 -AcDbArc - 50 -1.524516419169975 - 51 -7.590806272066473 - 0 -LINE - 5 -465 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255923.3851397643 - 20 -16964.57516647528 - 11 -255923.5047629486 - 21 -16960.08043886342 - 0 -ELLIPSE - 5 -466 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -255909.3455914413 - 20 -16960.08043886342 - 30 -0 - 11 --4.375286e-10 - 21 -21.60000000086583 - 31 -0 - 40 -0.4201486266968101 - 41 -1.570796326786386 - 42 -2.277981026602279 - 0 -ELLIPSE - 5 -467 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -255909.3455914413 - 20 -16960.08043886342 - 30 -0 - 11 --4.375286e-10 - 21 -21.60000000086583 - 31 -0 - 40 -0.4201486266968101 - 41 -0.863611626987514 - 42 -1.570796326803408 - 0 -LINE - 5 -468 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255931.3586763357 - 20 -16980.14649989848 - 11 -255920.5866514946 - 21 -16977.38748323465 - 0 -LINE - 5 -469 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255914.4782080637 - 20 -16978.01286606161 - 11 -255915.547637991 - 21 -16980.99350471963 - 0 -LINE - 5 -46A -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255931.3586763357 - 20 -16980.14651208388 - 11 -255936.2802127248 - 21 -16981.78682096109 - 0 -LINE - 5 -46B -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255936.2802127248 - 20 -16981.78682096109 - 11 -255945.8977432138 - 21 -16982.45815556952 - 0 -LINE - 5 -46C -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255945.8977432138 - 20 -16982.45815556952 - 11 -255952.8455914413 - 21 -16981.68045104879 - 0 -ARC - 5 -46D -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255945.8877535334 - 20 -16915.43556604394 - 40 -66.60928086729827 -100 -AcDbArc - 50 -74.65481712156559 - 51 -84.00408918623717 - 0 -ARC - 5 -46E -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255958.8427038578 - 20 -16956.39018656438 - 40 -23.74417378609639 -100 -AcDbArc - 50 -55.6600115736736 - 51 -78.65195057146462 - 0 -ARC - 5 -46F -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255952.6599209097 - 20 -16946.09056392946 - 40 -35.74329587309428 -100 -AcDbArc - 50 -37.95284360978441 - 51 -56.79000771970439 - 0 -ARC - 5 -470 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255964.5177862331 - 20 -16960.42018098404 - 40 -18.0310059913069 -100 -AcDbArc - 50 -358.9204017046412 - 51 -25.11481499733817 - 0 -LINE - 5 -471 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255931.3586763357 - 20 -16980.14649989848 - 11 -255925.9916875007 - 21 -16971.26928807745 - 0 -LINE - 5 -472 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255925.9916875007 - 20 -16971.26928807745 - 11 -255925.9916875007 - 21 -16960.08043886342 - 0 -LINE - 5 -473 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255925.9916875007 - 20 -16960.08043886342 - 11 -255925.9916875007 - 21 -16948.89158964939 - 0 -LINE - 5 -474 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255925.9916875007 - 20 -16948.89158964939 - 11 -255931.3586763357 - 21 -16940.01437782833 - 0 -LINE - 5 -475 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255931.3586763357 - 20 -16940.01436564296 - 11 -255936.2802127248 - 21 -16938.37405676574 - 0 -LINE - 5 -476 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255936.2802127248 - 20 -16938.37405676574 - 11 -255945.8977432138 - 21 -16937.70272215731 - 0 -LINE - 5 -477 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255945.8977432138 - 20 -16937.70272215731 - 11 -255952.8455914413 - 21 -16938.48042667805 - 0 -ARC - 5 -478 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255945.8877535334 - 20 -17004.7253116829 - 40 -66.60928086729827 -100 -AcDbArc - 50 -275.9959108137628 - 51 -285.3451828784344 - 0 -ARC - 5 -479 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255958.8427038578 - 20 -16963.77069116246 - 40 -23.74417378609639 -100 -AcDbArc - 50 -281.3480494285354 - 51 -304.3399884263264 - 0 -ARC - 5 -47A -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255952.6599209097 - 20 -16974.07031379738 - 40 -35.74329587309428 -100 -AcDbArc - 50 -303.2099922802956 - 51 -322.0471563902156 - 0 -ARC - 5 -47B -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255964.5177862331 - 20 -16959.7406967428 - 40 -18.0310059913069 -100 -AcDbArc - 50 -334.8851850026619 - 51 -1.079598295358819 - 0 -LINE - 5 -47C -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255931.3586763357 - 20 -16940.01437782833 - 11 -255920.5866514946 - 21 -16942.77339449215 - 0 -LINE - 5 -47D -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255980.7892561989 - 20 -16965.45109136029 - 11 -255980.7892561989 - 21 -16954.70978636655 - 0 -LINE - 5 -47E -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255980.7892561989 - 20 -16954.70978636655 - 11 -255979.9115668564 - 21 -16953.88198627053 - 0 -LINE - 5 -47F -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255979.9115668564 - 20 -16953.88198627053 - 11 -255978.9679138663 - 21 -16953.08040990304 - 0 -LINE - 5 -480 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255978.9679138663 - 20 -16953.08040990304 - 11 -255977.9762078532 - 21 -16952.31030207161 - 0 -LINE - 5 -481 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255977.9762078532 - 20 -16952.31030207161 - 11 -255976.9543594422 - 21 -16951.57690758385 - 0 -LINE - 5 -482 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255976.9543594422 - 20 -16951.57690758385 - 11 -255975.9202792581 - 21 -16950.8854712473 - 0 -LINE - 5 -483 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255975.9202792581 - 20 -16950.8854712473 - 11 -255974.8918779253 - 21 -16950.24123786959 - 0 -LINE - 5 -484 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255974.8918779253 - 20 -16950.24123786959 - 11 -255973.8870660691 - 21 -16949.64945225824 - 0 -LINE - 5 -485 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255973.8870660691 - 20 -16949.64945225824 - 11 -255972.9237543143 - 21 -16949.11535922091 - 0 -LINE - 5 -486 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255972.9237543143 - 20 -16949.11535922091 - 11 -255972.014028702 - 21 -16948.64158117022 - 0 -LINE - 5 -487 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255971.1466769398 - 20 -16948.22025093948 - 11 -255970.3046621522 - 21 -16947.84087896707 - 0 -LINE - 5 -488 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255970.3046621522 - 20 -16947.84087896707 - 11 -255969.4709474626 - 21 -16947.49297569138 - 0 -LINE - 5 -489 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255969.4709474626 - 20 -16947.49297569138 - 11 -255968.6284959954 - 21 -16947.16605155082 - 0 -LINE - 5 -48A -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255968.6284959954 - 20 -16947.16605155082 - 11 -255967.760270875 - 21 -16946.84961698372 - 0 -LINE - 5 -48B -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255967.760270875 - 20 -16946.84961698372 - 11 -255966.849235225 - 21 -16946.53318242856 - 0 -LINE - 5 -48C -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255966.849235225 - 20 -16946.53318242856 - 11 -255965.8783521697 - 21 -16946.2062583237 - 0 -LINE - 5 -48D -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255965.8783521697 - 20 -16946.2062583237 - 11 -255964.8358997522 - 21 -16945.86141456024 - 0 -LINE - 5 -48E -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255964.8358997522 - 20 -16945.86141456024 - 11 -255963.7314156918 - 21 -16945.50345884033 - 0 -LINE - 5 -48F -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255963.7314156918 - 20 -16945.50345884033 - 11 -255962.5797526261 - 21 -16945.14025831879 - 0 -LINE - 5 -490 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255962.5797526261 - 20 -16945.14025831879 - 11 -255961.3957631937 - 21 -16944.77968015046 - 0 -LINE - 5 -491 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255961.3957631937 - 20 -16944.77968015046 - 11 -255960.1943000327 - 21 -16944.42959149018 - 0 -LINE - 5 -492 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255960.1943000327 - 20 -16944.42959149018 - 11 -255958.9902157812 - 21 -16944.09785949284 - 0 -LINE - 5 -493 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255958.9902157812 - 20 -16944.09785949284 - 11 -255957.7983630772 - 21 -16943.79235131319 - 0 -LINE - 5 -494 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255957.7983630772 - 20 -16943.79235131319 - 11 -255956.6335945592 - 21 -16943.52093410616 - 0 -LINE - 5 -495 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255956.6335945592 - 20 -16943.52093410616 - 11 -255955.504829088 - 21 -16943.28972677324 - 0 -LINE - 5 -496 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255955.504829088 - 20 -16943.28972677324 - 11 -255954.3972504183 - 21 -16943.09785520264 - 0 -LINE - 5 -497 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255954.3972504183 - 20 -16943.09785520264 - 11 -255953.2901085278 - 21 -16942.94269702923 - 0 -LINE - 5 -498 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255953.2901085278 - 20 -16942.94269702923 - 11 -255952.1626533936 - 21 -16942.8216298879 - 0 -LINE - 5 -499 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255952.1626533936 - 20 -16942.8216298879 - 11 -255950.9941349938 - 21 -16942.73203141355 - 0 -LINE - 5 -49A -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255950.9941349938 - 20 -16942.73203141355 - 11 -255949.7638033056 - 21 -16942.67127924109 - 0 -LINE - 5 -49B -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255949.7638033056 - 20 -16942.67127924109 - 11 -255948.4509083068 - 21 -16942.63675100533 - 0 -LINE - 5 -49C -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255948.4509083068 - 20 -16942.63675100533 - 11 -255947.0346999745 - 21 -16942.62582434125 - 0 -LINE - 5 -49D -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255947.0346999745 - 20 -16942.62582434125 - 11 -255945.4935956204 - 21 -16942.63729779328 - 0 -LINE - 5 -49E -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255945.4935956204 - 20 -16942.63729779328 - 11 -255943.8026818886 - 21 -16942.67565354451 - 0 -LINE - 5 -49F -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255943.8026818886 - 20 -16942.67565354451 - 11 -255941.9362127572 - 21 -16942.74679468757 - 0 -LINE - 5 -4A0 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255941.9362127572 - 20 -16942.74679468757 - 11 -255939.8684422046 - 21 -16942.85662431522 - 0 -LINE - 5 -4A1 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255939.8684422046 - 20 -16942.85662431522 - 11 -255937.5736242083 - 21 -16943.01104552004 - 0 -LINE - 5 -4A2 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255937.5736242083 - 20 -16943.01104552004 - 11 -255935.0260127471 - 21 -16943.21596139479 - 0 -LINE - 5 -4A3 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255935.0260127471 - 20 -16943.21596139479 - 11 -255932.1998617982 - 21 -16943.47727503206 - 0 -LINE - 5 -4A4 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255932.1998617982 - 20 -16943.47727503206 - 11 -255929.0694253403 - 21 -16943.80088952459 - 0 -LINE - 5 -4A5 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255980.7892561989 - 20 -16965.45109136029 - 11 -255979.9115668564 - 21 -16966.27889145631 - 0 -LINE - 5 -4A6 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255979.9115668564 - 20 -16966.27889145631 - 11 -255978.9679138663 - 21 -16967.0804678238 - 0 -LINE - 5 -4A7 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255978.9679138663 - 20 -16967.0804678238 - 11 -255977.9762078532 - 21 -16967.85057565522 - 0 -LINE - 5 -4A8 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255977.9762078532 - 20 -16967.85057565522 - 11 -255976.9543594422 - 21 -16968.58397014298 - 0 -LINE - 5 -4A9 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255976.9543594422 - 20 -16968.58397014298 - 11 -255975.9202792581 - 21 -16969.27540647954 - 0 -LINE - 5 -4AA -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255975.9202792581 - 20 -16969.27540647954 - 11 -255974.8918779253 - 21 -16969.91963985724 - 0 -LINE - 5 -4AB -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255974.8918779253 - 20 -16969.91963985724 - 11 -255973.8870660691 - 21 -16970.51142546857 - 0 -LINE - 5 -4AC -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255973.8870660691 - 20 -16970.51142546857 - 11 -255972.9237543143 - 21 -16971.04551850593 - 0 -LINE - 5 -4AD -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255972.9237543143 - 20 -16971.04551850593 - 11 -255972.014028702 - 21 -16971.51929655661 - 0 -LINE - 5 -4AE -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255972.014028702 - 20 -16971.51929655661 - 11 -255971.1466769398 - 21 -16971.94062678736 - 0 -LINE - 5 -4AF -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255971.1466769398 - 20 -16971.94062678736 - 11 -255970.3046621522 - 21 -16972.31999875977 - 0 -LINE - 5 -4B0 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255970.3046621522 - 20 -16972.31999875977 - 11 -255969.4709474626 - 21 -16972.66790203545 - 0 -LINE - 5 -4B1 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255969.4709474626 - 20 -16972.66790203545 - 11 -255968.6284959954 - 21 -16972.99482617602 - 0 -LINE - 5 -4B2 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255968.6284959954 - 20 -16972.99482617602 - 11 -255967.760270875 - 21 -16973.31126074309 - 0 -LINE - 5 -4B3 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255967.760270875 - 20 -16973.31126074309 - 11 -255966.849235225 - 21 -16973.62769529824 - 0 -LINE - 5 -4B4 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255966.849235225 - 20 -16973.62769529824 - 11 -255965.8783521697 - 21 -16973.95461940313 - 0 -LINE - 5 -4B5 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255965.8783521697 - 20 -16973.95461940313 - 11 -255964.8358997522 - 21 -16974.29946316658 - 0 -LINE - 5 -4B6 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255964.8358997522 - 20 -16974.29946316658 - 11 -255963.7314156918 - 21 -16974.65741888648 - 0 -LINE - 5 -4B7 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255963.7314156918 - 20 -16974.65741888648 - 11 -255962.5797526261 - 21 -16975.02061940804 - 0 -LINE - 5 -4B8 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255962.5797526261 - 20 -16975.02061940804 - 11 -255961.3957631937 - 21 -16975.38119757637 - 0 -LINE - 5 -4B9 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255961.3957631937 - 20 -16975.38119757637 - 11 -255960.1943000327 - 21 -16975.73128623663 - 0 -LINE - 5 -4BA -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255960.1943000327 - 20 -16975.73128623663 - 11 -255958.9902157812 - 21 -16976.063018234 - 0 -LINE - 5 -4BB -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255958.9902157812 - 20 -16976.063018234 - 11 -255957.7983630772 - 21 -16976.36852641365 - 0 -LINE - 5 -4BC -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255957.7983630772 - 20 -16976.36852641365 - 11 -255956.6335945592 - 21 -16976.63994362068 - 0 -LINE - 5 -4BD -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255956.6335945592 - 20 -16976.63994362068 - 11 -255955.504829088 - 21 -16976.8711509536 - 0 -LINE - 5 -4BE -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255955.504829088 - 20 -16976.8711509536 - 11 -255954.3972504183 - 21 -16977.0630225242 - 0 -LINE - 5 -4BF -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255954.3972504183 - 20 -16977.0630225242 - 11 -255953.2901085278 - 21 -16977.21818069761 - 0 -LINE - 5 -4C0 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255953.2901085278 - 20 -16977.21818069761 - 11 -255952.1626533936 - 21 -16977.33924783893 - 0 -LINE - 5 -4C1 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255952.1626533936 - 20 -16977.33924783893 - 11 -255950.9941349938 - 21 -16977.42884631326 - 0 -LINE - 5 -4C2 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255950.9941349938 - 20 -16977.42884631326 - 11 -255949.7638033056 - 21 -16977.48959848575 - 0 -LINE - 5 -4C3 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255949.7638033056 - 20 -16977.48959848575 - 11 -255948.4509083068 - 21 -16977.52412672151 - 0 -LINE - 5 -4C4 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255948.4509083068 - 20 -16977.52412672151 - 11 -255947.0346999745 - 21 -16977.53505338559 - 0 -LINE - 5 -4C5 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255947.0346999745 - 20 -16977.53505338559 - 11 -255945.4935956204 - 21 -16977.52357993356 - 0 -LINE - 5 -4C6 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255945.4935956204 - 20 -16977.52357993356 - 11 -255943.8026818886 - 21 -16977.48522418233 - 0 -LINE - 5 -4C7 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255943.8026818886 - 20 -16977.48522418233 - 11 -255941.9362127572 - 21 -16977.41408303923 - 0 -LINE - 5 -4C8 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255941.9362127572 - 20 -16977.41408303923 - 11 -255939.8684422046 - 21 -16977.30425341162 - 0 -LINE - 5 -4C9 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255939.8684422046 - 20 -16977.30425341162 - 11 -255937.5736242083 - 21 -16977.14983220676 - 0 -LINE - 5 -4CA -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255937.5736242083 - 20 -16977.14983220676 - 11 -255935.0260127471 - 21 -16976.94491633204 - 0 -LINE - 5 -4CB -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255935.0260127471 - 20 -16976.94491633204 - 11 -255932.1998617982 - 21 -16976.68360269475 - 0 -LINE - 5 -4CC -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255932.1998617982 - 20 -16976.68360269475 - 11 -255929.0694253403 - 21 -16976.35998820224 - 0 -LINE - 5 -4CD -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255902.9436449546 - 20 -16948.18570952079 - 11 -255902.9945215014 - 21 -16947.50279576575 - 0 -LINE - 5 -4CE -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255902.9945215014 - 20 -16947.50279576575 - 11 -255903.0355508938 - 21 -16946.97840756433 - 0 -LINE - 5 -4CF -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.0355508938 - 20 -16946.97840756433 - 11 -255903.0712089978 - 21 -16946.57761555732 - 0 -LINE - 5 -4D0 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.0712089978 - 20 -16946.57761555732 - 11 -255903.1059716787 - 21 -16946.26549038535 - 0 -LINE - 5 -4D1 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.1059716787 - 20 -16946.26549038535 - 11 -255903.1443148021 - 21 -16946.00710268917 - 0 -LINE - 5 -4D2 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.1443148021 - 20 -16946.00710268917 - 11 -255903.1907142337 - 21 -16945.76752310955 - 0 -LINE - 5 -4D3 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.1907142337 - 20 -16945.76752310955 - 11 -255903.2496458391 - 21 -16945.51182228719 - 0 -LINE - 5 -4D4 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.2496458391 - 20 -16945.51182228719 - 11 -255903.3255854838 - 21 -16945.2050708628 - 0 -LINE - 5 -4D5 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255902.9436449546 - 20 -16971.97516820605 - 11 -255902.9945215014 - 21 -16972.65808196109 - 0 -LINE - 5 -4D6 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255902.9945215014 - 20 -16972.65808196109 - 11 -255903.0355508938 - 21 -16973.18247016251 - 0 -LINE - 5 -4D7 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.1907142337 - 20 -16974.39335461728 - 11 -255903.2496458391 - 21 -16974.64905543965 - 0 -LINE - 5 -4D8 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.0355508938 - 20 -16973.18247016251 - 11 -255903.0712089978 - 21 -16973.58326216952 - 0 -LINE - 5 -4D9 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.0712089978 - 20 -16973.58326216952 - 11 -255903.1059716787 - 21 -16973.89538734149 - 0 -LINE - 5 -4DA -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.1059716787 - 20 -16973.89538734149 - 11 -255903.1443148021 - 21 -16974.15377503767 - 0 -LINE - 5 -4DB -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.1443148021 - 20 -16974.15377503767 - 11 -255903.1907142337 - 21 -16974.39335461728 - 0 -LINE - 5 -4DC -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.2496458391 - 20 -16974.64905543965 - 11 -255903.3255854838 - 21 -16974.95580686404 - 0 -ENDBLK - 5 -1B3 -330 -1B1 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1B5 -330 -1B4 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*U4 - 70 - 0 - 10 -0 - 20 -0 - 3 -*U4 - 1 - - 0 -LWPOLYLINE - 5 -4DD -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -880000.2756987195 - 20 -290303.5326859512 - 10 -880023.2756987197 - 20 -290303.5326859512 - 10 -880023.2756987197 - 20 -290253.5326859512 - 10 -880000.2756987195 - 20 -290253.5326859512 - 10 -880000.2756987195 - 20 -290303.5326859512 - 0 -HATCH - 5 -4DE -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -880023.2756987197 - 20 -290253.5326859512 - 11 -880023.2756987197 - 21 -290303.5326859512 - 72 - 1 - 10 -880023.2756987197 - 20 -290303.5326859512 - 11 -880000.2756987195 - 21 -290303.5326859512 - 72 - 1 - 10 -880000.2756987195 - 20 -290303.5326859512 - 11 -880000.2756987195 - 21 -290253.5326859512 - 72 - 1 - 10 -880000.2756987195 - 20 -290253.5326859512 - 11 -880023.2756987197 - 21 -290253.5326859512 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -4DF -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879552.3932570594 - 20 -290336.3959268102 - 11 -879552.3932570594 - 21 -290386.3959268102 - 72 - 1 - 10 -879552.3932570594 - 20 -290386.3959268102 - 11 -879529.3932570594 - 21 -290386.3959268102 - 72 - 1 - 10 -879529.3932570594 - 20 -290386.3959268102 - 11 -879529.3932570594 - 21 -290336.3959268102 - 72 - 1 - 10 -879529.3932570594 - 20 -290336.3959268102 - 11 -879552.3932570594 - 21 -290336.3959268102 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4E0 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879529.3932570594 - 20 -290386.3959268102 - 10 -879552.3932570594 - 20 -290386.3959268102 - 10 -879552.3932570594 - 20 -290336.3959268102 - 10 -879529.3932570594 - 20 -290336.3959268102 - 10 -879529.3932570594 - 20 -290386.3959268102 - 0 -HATCH - 5 -4E1 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879199.5286617092 - 20 -291789.1693454167 - 11 -879199.5286617092 - 21 -291839.1693454168 - 72 - 1 - 10 -879199.5286617092 - 20 -291839.1693454168 - 11 -879176.528661709 - 21 -291839.1693454168 - 72 - 1 - 10 -879176.528661709 - 20 -291839.1693454168 - 11 -879176.528661709 - 21 -291789.1693454167 - 72 - 1 - 10 -879176.528661709 - 20 -291789.1693454167 - 11 -879199.5286617092 - 21 -291789.1693454167 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4E2 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879176.528661709 - 20 -291839.1693454168 - 10 -879199.5286617092 - 20 -291839.1693454168 - 10 -879199.5286617092 - 20 -291789.1693454167 - 10 -879176.528661709 - 20 -291789.1693454167 - 10 -879176.528661709 - 20 -291839.1693454168 - 0 -HATCH - 5 -4E3 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 5 - 72 - 1 - 10 -879549.3932570581 - 20 -290273.5326859524 - 11 -879549.3932570581 - 21 -290276.5326859521 - 72 - 1 - 10 -879549.3932570581 - 20 -290276.5326859521 - 11 -879529.3932570578 - 21 -290276.5326859523 - 72 - 1 - 10 -879529.3932570578 - 20 -290276.5326859523 - 11 -879529.3932570578 - 21 -290253.5326859523 - 72 - 1 - 10 -879529.3932570578 - 20 -290253.5326859523 - 11 -879549.3932570581 - 21 -290253.5326859523 - 72 - 1 - 10 -879549.3932570581 - 20 -290253.5326859523 - 11 -879549.3932570581 - 21 -290273.5326859524 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4E4 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -879549.3932570581 - 20 -290273.5326859524 - 10 -879549.3932570581 - 20 -290253.5326859523 - 10 -879529.3932570578 - 20 -290253.5326859523 - 10 -879529.3932570578 - 20 -290276.5326859523 - 10 -879549.3932570581 - 20 -290276.5326859521 - 10 -879549.3932570581 - 20 -290273.5326859524 - 0 -HATCH - 5 -4E5 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 5 - 72 - 1 - 10 -879699.8932570573 - 20 -290273.5326859512 - 11 -879699.8932570573 - 21 -290276.5326859509 - 72 - 1 - 10 -879699.8932570573 - 20 -290276.5326859509 - 11 -879679.8932570572 - 21 -290276.5326859512 - 72 - 1 - 10 -879679.8932570572 - 20 -290276.5326859512 - 11 -879679.8932570572 - 21 -290253.5326859512 - 72 - 1 - 10 -879679.8932570572 - 20 -290253.5326859512 - 11 -879699.8932570573 - 21 -290253.5326859512 - 72 - 1 - 10 -879699.8932570573 - 20 -290253.5326859512 - 11 -879699.8932570573 - 21 -290273.5326859512 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4E6 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -879699.8932570573 - 20 -290273.5326859512 - 10 -879699.8932570573 - 20 -290253.5326859512 - 10 -879679.8932570572 - 20 -290253.5326859512 - 10 -879679.8932570572 - 20 -290276.5326859512 - 10 -879699.8932570573 - 20 -290276.5326859509 - 10 -879699.8932570573 - 20 -290273.5326859512 - 0 -HATCH - 5 -4E7 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -880346.2756987192 - 20 -291839.1693454168 - 11 -880296.2756987197 - 21 -291839.1693454168 - 72 - 1 - 10 -880296.2756987197 - 20 -291839.1693454168 - 11 -880296.2756987197 - 21 -291816.1693454167 - 72 - 1 - 10 -880296.2756987197 - 20 -291816.1693454167 - 11 -880346.2756987192 - 21 -291816.1693454167 - 72 - 1 - 10 -880346.2756987192 - 20 -291816.1693454167 - 11 -880346.2756987192 - 21 -291839.1693454168 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4E8 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -880296.2756987197 - 20 -291816.1693454167 - 10 -880296.2756987197 - 20 -291839.1693454168 - 10 -880346.2756987192 - 20 -291839.1693454168 - 10 -880346.2756987192 - 20 -291816.1693454167 - 10 -880296.2756987197 - 20 -291816.1693454167 - 0 -LINE - 5 -4E9 -100 -AcDbEntity - 8 -coloumn - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -880346.2756987192 - 20 -291816.1693454167 - 11 -880346.2756987192 - 21 -291816.1693454167 - 0 -HATCH - 5 -4EA -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879226.528661709 - 20 -291193.1693454167 - 11 -879176.528661709 - 21 -291193.1693454167 - 72 - 1 - 10 -879176.528661709 - 20 -291193.1693454167 - 11 -879176.528661709 - 21 -291170.1693454168 - 72 - 1 - 10 -879176.528661709 - 20 -291170.1693454168 - 11 -879226.528661709 - 21 -291170.1693454168 - 72 - 1 - 10 -879226.528661709 - 20 -291170.1693454168 - 11 -879226.528661709 - 21 -291193.1693454167 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4EB -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879176.528661709 - 20 -291170.1693454168 - 10 -879176.528661709 - 20 -291193.1693454167 - 10 -879226.528661709 - 20 -291193.1693454167 - 10 -879226.528661709 - 20 -291170.1693454168 - 10 -879176.528661709 - 20 -291170.1693454168 - 0 -HATCH - 5 -4EC -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -880323.2756987195 - 20 -291193.1693454167 - 11 -880323.2756987195 - 21 -291143.1693454167 - 72 - 1 - 10 -880323.2756987195 - 20 -291143.1693454167 - 11 -880346.2756987192 - 21 -291143.1693454167 - 72 - 1 - 10 -880346.2756987192 - 20 -291143.1693454167 - 11 -880346.2756987192 - 21 -291193.1693454167 - 72 - 1 - 10 -880346.2756987192 - 20 -291193.1693454167 - 11 -880323.2756987195 - 21 -291193.1693454167 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4ED -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -880346.2756987192 - 20 -291143.1693454167 - 10 -880323.2756987195 - 20 -291143.1693454167 - 10 -880323.2756987195 - 20 -291193.1693454167 - 10 -880346.2756987192 - 20 -291193.1693454167 - 10 -880346.2756987192 - 20 -291143.1693454167 - 0 -HATCH - 5 -4EE -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879176.528661709 - 20 -290556.3959268099 - 11 -879176.528661709 - 21 -290506.3959268099 - 72 - 1 - 10 -879176.528661709 - 20 -290506.3959268099 - 11 -879199.5286617092 - 21 -290506.3959268099 - 72 - 1 - 10 -879199.5286617092 - 20 -290506.3959268099 - 11 -879199.5286617092 - 21 -290556.3959268099 - 72 - 1 - 10 -879199.5286617092 - 20 -290556.3959268099 - 11 -879176.528661709 - 21 -290556.3959268099 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4EF -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879199.5286617092 - 20 -290506.3959268099 - 10 -879176.528661709 - 20 -290506.3959268099 - 10 -879176.528661709 - 20 -290556.3959268099 - 10 -879199.5286617092 - 20 -290556.3959268099 - 10 -879199.5286617092 - 20 -290506.3959268099 - 0 -HATCH - 5 -4F0 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -880323.2756987195 - 20 -290556.3959268099 - 11 -880323.2756987195 - 21 -290506.3959268099 - 72 - 1 - 10 -880323.2756987195 - 20 -290506.3959268099 - 11 -880346.2756987192 - 21 -290506.3959268099 - 72 - 1 - 10 -880346.2756987192 - 20 -290506.3959268099 - 11 -880346.2756987192 - 21 -290556.3959268099 - 72 - 1 - 10 -880346.2756987192 - 20 -290556.3959268099 - 11 -880323.2756987195 - 21 -290556.3959268099 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4F1 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -880346.2756987192 - 20 -290506.3959268099 - 10 -880323.2756987195 - 20 -290506.3959268099 - 10 -880323.2756987195 - 20 -290556.3959268099 - 10 -880346.2756987192 - 20 -290556.3959268099 - 10 -880346.2756987192 - 20 -290506.3959268099 - 0 -HATCH - 5 -4F2 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879717.8932570579 - 20 -291839.1693454168 - 11 -879667.893257058 - 21 -291839.1693454168 - 72 - 1 - 10 -879667.893257058 - 20 -291839.1693454168 - 11 -879667.893257058 - 21 -291816.1693454167 - 72 - 1 - 10 -879667.893257058 - 20 -291816.1693454167 - 11 -879717.8932570579 - 21 -291816.1693454167 - 72 - 1 - 10 -879717.8932570579 - 20 -291816.1693454167 - 11 -879717.8932570579 - 21 -291839.1693454168 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4F3 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879667.893257058 - 20 -291816.1693454167 - 10 -879667.893257058 - 20 -291839.1693454168 - 10 -879717.8932570579 - 20 -291839.1693454168 - 10 -879717.8932570579 - 20 -291816.1693454167 - 10 -879667.893257058 - 20 -291816.1693454167 - 0 -HATCH - 5 -4F4 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 5 - 72 - 1 - 10 -879699.8932570581 - 20 -290383.3959268093 - 11 -879699.8932570581 - 21 -290386.3959268088 - 72 - 1 - 10 -879699.8932570581 - 20 -290386.3959268088 - 11 -879679.8932570579 - 21 -290386.3959268091 - 72 - 1 - 10 -879679.8932570579 - 20 -290386.3959268091 - 11 -879679.8932570579 - 21 -290363.3959268093 - 72 - 1 - 10 -879679.8932570579 - 20 -290363.3959268093 - 11 -879699.8932570581 - 21 -290363.3959268093 - 72 - 1 - 10 -879699.8932570581 - 20 -290363.3959268093 - 11 -879699.8932570581 - 21 -290383.3959268093 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4F5 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -879699.8932570581 - 20 -290383.3959268093 - 10 -879699.8932570581 - 20 -290363.3959268093 - 10 -879679.8932570579 - 20 -290363.3959268093 - 10 -879679.8932570579 - 20 -290386.3959268091 - 10 -879699.8932570581 - 20 -290386.3959268088 - 10 -879699.8932570581 - 20 -290383.3959268093 - 0 -HATCH - 5 -4F6 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879226.528661709 - 20 -290870.1693454167 - 11 -879176.528661709 - 21 -290870.1693454167 - 72 - 1 - 10 -879176.528661709 - 20 -290870.1693454167 - 11 -879176.528661709 - 21 -290847.1693454167 - 72 - 1 - 10 -879176.528661709 - 20 -290847.1693454167 - 11 -879226.528661709 - 21 -290847.1693454167 - 72 - 1 - 10 -879226.528661709 - 20 -290847.1693454167 - 11 -879226.528661709 - 21 -290870.1693454167 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4F7 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879176.528661709 - 20 -290847.1693454167 - 10 -879176.528661709 - 20 -290870.1693454167 - 10 -879226.528661709 - 20 -290870.1693454167 - 10 -879226.528661709 - 20 -290847.1693454167 - 10 -879176.528661709 - 20 -290847.1693454167 - 0 -HATCH - 5 -4F8 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -880346.2756987192 - 20 -290870.1693454167 - 11 -880296.2756987197 - 21 -290870.1693454167 - 72 - 1 - 10 -880296.2756987197 - 20 -290870.1693454167 - 11 -880296.2756987197 - 21 -290847.1693454167 - 72 - 1 - 10 -880296.2756987197 - 20 -290847.1693454167 - 11 -880346.2756987192 - 21 -290847.1693454167 - 72 - 1 - 10 -880346.2756987192 - 20 -290847.1693454167 - 11 -880346.2756987192 - 21 -290870.1693454167 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4F9 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -880296.2756987197 - 20 -290847.1693454167 - 10 -880296.2756987197 - 20 -290870.1693454167 - 10 -880346.2756987192 - 20 -290870.1693454167 - 10 -880346.2756987192 - 20 -290847.1693454167 - 10 -880296.2756987197 - 20 -290847.1693454167 - 0 -HATCH - 5 -4FA -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879199.5286617323 - 20 -290136.395926983 - 11 -879199.5286617323 - 21 -290186.395926983 - 72 - 1 - 10 -879199.5286617323 - 20 -290186.395926983 - 11 -879176.5286617324 - 21 -290186.395926983 - 72 - 1 - 10 -879176.5286617324 - 20 -290186.395926983 - 11 -879176.5286617324 - 21 -290136.395926983 - 72 - 1 - 10 -879176.5286617324 - 20 -290136.395926983 - 11 -879199.5286617323 - 21 -290136.395926983 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4FB -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879176.5286617324 - 20 -290186.395926983 - 10 -879199.5286617323 - 20 -290186.395926983 - 10 -879199.5286617323 - 20 -290136.395926983 - 10 -879176.5286617324 - 20 -290136.395926983 - 10 -879176.5286617324 - 20 -290186.395926983 - 0 -HATCH - 5 -4FC -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -880323.2756987195 - 20 -291516.1693466697 - 11 -880323.2756987195 - 21 -291466.1693466697 - 72 - 1 - 10 -880323.2756987195 - 20 -291466.1693466697 - 11 -880346.2756987192 - 21 -291466.1693466697 - 72 - 1 - 10 -880346.2756987192 - 20 -291466.1693466697 - 11 -880346.2756987192 - 21 -291516.1693466697 - 72 - 1 - 10 -880346.2756987192 - 20 -291516.1693466697 - 11 -880323.2756987195 - 21 -291516.1693466697 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4FD -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -880346.2756987192 - 20 -291466.1693466697 - 10 -880323.2756987195 - 20 -291466.1693466697 - 10 -880323.2756987195 - 20 -291516.1693466697 - 10 -880346.2756987192 - 20 -291516.1693466697 - 10 -880346.2756987192 - 20 -291466.1693466697 - 0 -HATCH - 5 -4FE -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879176.528661709 - 20 -291516.1693466697 - 11 -879176.528661709 - 21 -291466.1693466697 - 72 - 1 - 10 -879176.528661709 - 20 -291466.1693466697 - 11 -879199.5286617092 - 21 -291466.1693466697 - 72 - 1 - 10 -879199.5286617092 - 20 -291466.1693466697 - 11 -879199.5286617092 - 21 -291516.1693466697 - 72 - 1 - 10 -879199.5286617092 - 20 -291516.1693466697 - 11 -879176.528661709 - 21 -291516.1693466697 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4FF -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879199.5286617092 - 20 -291466.1693466697 - 10 -879176.528661709 - 20 -291466.1693466697 - 10 -879176.528661709 - 20 -291516.1693466697 - 10 -879199.5286617092 - 20 -291516.1693466697 - 10 -879199.5286617092 - 20 -291466.1693466697 - 0 -HATCH - 5 -500 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879667.893257058 - 20 -291516.1693466697 - 11 -879667.893257058 - 21 -291466.1693466697 - 72 - 1 - 10 -879667.893257058 - 20 -291466.1693466697 - 11 -879690.893257058 - 21 -291466.1693466697 - 72 - 1 - 10 -879690.893257058 - 20 -291466.1693466697 - 11 -879690.893257058 - 21 -291516.1693466697 - 72 - 1 - 10 -879690.893257058 - 20 -291516.1693466697 - 11 -879667.893257058 - 21 -291516.1693466697 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -501 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879690.893257058 - 20 -291466.1693466697 - 10 -879667.893257058 - 20 -291466.1693466697 - 10 -879667.893257058 - 20 -291516.1693466697 - 10 -879690.893257058 - 20 -291516.1693466697 - 10 -879690.893257058 - 20 -291466.1693466697 - 0 -HATCH - 5 -502 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879359.528661709 - 20 -291516.1693466697 - 11 -879359.528661709 - 21 -291466.1693466697 - 72 - 1 - 10 -879359.528661709 - 20 -291466.1693466697 - 11 -879382.528661709 - 21 -291466.1693466697 - 72 - 1 - 10 -879382.528661709 - 20 -291466.1693466697 - 11 -879382.528661709 - 21 -291516.1693466697 - 72 - 1 - 10 -879382.528661709 - 20 -291516.1693466697 - 11 -879359.528661709 - 21 -291516.1693466697 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -503 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879382.528661709 - 20 -291466.1693466697 - 10 -879359.528661709 - 20 -291466.1693466697 - 10 -879359.528661709 - 20 -291516.1693466697 - 10 -879382.528661709 - 20 -291516.1693466697 - 10 -879382.528661709 - 20 -291466.1693466697 - 0 -HATCH - 5 -504 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879409.528661709 - 20 -291839.1693454168 - 11 -879359.528661709 - 21 -291839.1693454168 - 72 - 1 - 10 -879359.528661709 - 20 -291839.1693454168 - 11 -879359.528661709 - 21 -291816.1693454167 - 72 - 1 - 10 -879359.528661709 - 20 -291816.1693454167 - 11 -879409.528661709 - 21 -291816.1693454167 - 72 - 1 - 10 -879409.528661709 - 20 -291816.1693454167 - 11 -879409.528661709 - 21 -291839.1693454168 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -ENDBLK - 5 -1B6 -330 -1B4 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1B8 -330 -1B7 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -WELL10 - 70 - 0 - 10 -0 - 20 -0 - 3 -WELL10 - 1 - - 0 -LINE - 5 -505 -100 -AcDbEntity - 8 -Symbols - 6 -ByLayer - 62 - 5 -370 - -1 -100 -AcDbLine - 10 -0 - 20 -0 - 11 -0 - 21 -2.287486164789693 - 0 -LINE - 5 -506 -100 -AcDbEntity - 8 -Symbols - 6 -ByLayer - 62 - 5 -370 - -1 -100 -AcDbLine - 10 --0.7729281121480654 - 20 -2.287486164789693 - 11 -0 - 21 -2.287486164789693 - 0 -LINE - 5 -507 -100 -AcDbEntity - 8 -Symbols - 6 -ByLayer - 62 - 5 -370 - -1 -100 -AcDbLine - 10 -0.7729281121487475 - 20 -2.287486164789693 - 11 -0 - 21 -2.287486164789693 - 0 -LINE - 5 -508 -100 -AcDbEntity - 8 -Symbols - 6 -ByLayer - 62 - 5 -370 - -1 -100 -AcDbLine - 10 -0 - 20 -2.287486164789693 - 11 -0 - 21 -2.74559999999974 - 0 -LINE - 5 -509 -100 -AcDbEntity - 8 -Symbols - 6 -ByLayer - 62 - 5 -370 - -1 -100 -AcDbLine - 10 --0.7729281121480654 - 20 -2.287486164789693 - 11 --0.7729281121480654 - 21 -2.74559999999974 - 0 -LINE - 5 -50A -100 -AcDbEntity - 8 -Symbols - 6 -ByLayer - 62 - 5 -370 - -1 -100 -AcDbLine - 10 -0.7729281121487475 - 20 -2.287486164789693 - 11 -0.7729281121487475 - 21 -2.74559999999974 - 0 -ENDBLK - 5 -1B9 -330 -1B7 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1BB -330 -1BA -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -Basin 22 - 70 - 0 - 10 -0 - 20 -0 - 3 -Basin 22 - 1 - - 0 -ARC - 5 -50B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -0.1321794967992105 - 20 --0.325504014951008 - 40 -0.1437500000000217 -100 -AcDbArc - 50 -293.1162141335525 - 51 -40.8351460069247 - 0 -LINE - 5 -50C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -0.2409398981296249 - 20 --0.2315080703446313 - 11 -0.1950320817833813 - 21 --0.1783892623904535 - 0 -ARC - 5 -50D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.0007366406113647 - 20 --0.3475819626819998 - 40 -0.2587500000000005 -100 -AcDbArc - 50 -40.83514600694555 - 51 -88.78463085452169 - 0 -ARC - 5 -50E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.0007366406113647 - 20 --0.3475819626819998 - 40 -0.2587500000000005 -100 -AcDbArc - 50 -92.10640002390524 - 51 -139.0772043571666 - 0 -ARC - 5 -50F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -5.223716119770585 - 20 --4.8767844306374 - 40 -7.173125000041213 -100 -AcDbArc - 50 -139.0772043571666 - 51 -139.6291149363638 - 0 -ARC - 5 -510 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.1317366057217555 - 20 --0.3236273944457366 - 40 -0.1437500000000047 -100 -AcDbArc - 50 -139.6291149363638 - 51 -246.068976754325 - 0 -ARC - 5 -511 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -0.0023769810307499 - 20 --0.0214247530386445 - 40 -0.4743750000000289 -100 -AcDbArc - 50 -246.0689767543184 - 51 -293.1162141335381 - 0 -ARC - 5 -512 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.0031413677898513 - 20 --0.1174269241952572 - 40 -0.0171395037096485 -100 -AcDbArc - 50 -121.873286941506 - 51 -54.44344209893295 - 0 -ARC - 5 -513 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.0031413677898513 - 20 --0.1174269241952572 - 40 -0.0157020037096485 -100 -AcDbArc - 50 -127.4943272133481 - 51 -44.36692534066547 - 0 -ARC - 5 -514 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -0.1321794967992105 - 20 --0.3255040149509796 - 40 -0.1725000000000157 -100 -AcDbArc - 50 -293.1162141335453 - 51 -40.83514600693052 - 0 -LINE - 5 -515 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -0.2626919783957078 - 20 --0.2127088814233389 - 11 -0.2167841620494642 - 21 --0.1595900734692179 - 0 -ARC - 5 -516 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.0007366406113647 - 20 --0.3475819626820566 - 40 -0.287499999999988 -100 -AcDbArc - 50 -40.83514600695138 - 51 -88.64261667473257 - 0 -ARC - 5 -517 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.0007366406113647 - 20 --0.3475819626820566 - 40 -0.287499999999988 -100 -AcDbArc - 50 -92.15127297321656 - 51 -139.0772043571679 - 0 -ARC - 5 -518 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -5.223716119606535 - 20 --4.876784430512087 - 40 -7.201874999835127 -100 -AcDbArc - 50 -139.0772043570661 - 51 -139.6291149362762 - 0 -ARC - 5 -519 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.1317366057216418 - 20 --0.3236273944457366 - 40 -0.1725000000000949 -100 -AcDbArc - 50 -139.6291149363488 - 51 -246.0689767543001 - 0 -ARC - 5 -51A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -0.0023769810306362 - 20 --0.0214247530384455 - 40 -0.5031250000002138 -100 -AcDbArc - 50 -246.0689767543396 - 51 -293.1162141335489 - 0 -ARC - 5 -51B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.0007366406113647 - 20 --0.3475819626820566 - 40 -0.3162499999999756 -100 -AcDbArc - 50 -107.7441195829452 - 51 -139.077204357162 - 0 -ARC - 5 -51C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -5.223716119607558 - 20 --4.876784430510893 - 40 -7.230624999835111 -100 -AcDbArc - 50 -139.0772043570778 - 51 -139.6291149362888 - 0 -ARC - 5 -51D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.1317366057217555 - 20 --0.3236273944457366 - 40 -0.201250000000043 -100 -AcDbArc - 50 -139.6291149363279 - 51 -148.2007353781487 - 0 -ARC - 5 -51E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.1503825840422337 - 20 --0.2104289250981139 - 40 -0.2111486022219079 -100 -AcDbArc - 50 -94.29349916300878 - 51 -224.6439515676748 - 0 -ARC - 5 -51F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.1663222906667556 - 20 --0.1723728326169294 - 40 -0.14375 -100 -AcDbArc - 50 -61.22222211535271 - 51 -198.3295940544968 - 0 -ARC - 5 -520 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -0.1503905689735916 - 20 --0.2108791257136318 - 40 -0.2113434224539952 -100 -AcDbArc - 50 -315.6271807366346 - 51 -85.71263689210166 - 0 -LINE - 5 -521 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --0.1661903476086195 - 20 -0.0001271169223003 - 11 -0.1661903476086195 - 21 --0.0001271169223003 - 0 -ARC - 5 -522 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.0020133104299589 - 20 --0.3475769123552936 - 40 -0.3162499999999756 -100 -AcDbArc - 50 -40.46948986680843 - 51 -71.80257464102542 - 0 -ARC - 5 -523 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --5.262135779191737 - 20 --4.835303870623931 - 40 -7.230624999835111 -100 -AcDbArc - 50 -39.91757928768392 - 51 -40.4694898668893 - 0 -ARC - 5 -524 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -0.1291720736139155 - 20 --0.3246595125990836 - 40 -0.201250000000043 -100 -AcDbArc - 50 -31.34595884581941 - 51 -39.91757928764348 - 0 -ARC - 5 -525 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -0.1649533410770232 - 20 --0.1736833125678743 - 40 -0.14375 -100 -AcDbArc - 50 -341.2171001694725 - 51 -118.3244721086172 - 0 -ELLIPSE - 5 -526 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0027327899849183 - 20 --0.028747918133206 - 30 -0 - 11 --0.0153089308747744 - 21 --0.0153089308747744 - 31 -0 - 40 -0.9999999999999403 - 41 --0.202915411692806 - 42 -4.914963447533809 - 0 -ELLIPSE - 5 -527 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.04429547158162 - 20 --0.0287838894633978 - 30 -0 - 11 --0.0057408490780428 - 21 --0.0057408490780428 - 31 -0 - 40 -0.9999999999998058 - 41 -5.036668871464866 - 42 -5.958564471470781 - 0 -ELLIPSE - 5 -528 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.04429547158162 - 20 --0.0287838894633978 - 30 -0 - 11 -0.0034445094468257 - 21 --0.0034445094468257 - 31 -0 - 40 -0.9999999999988096 - 41 --0.7853981633980407 - 42 -5.497787143781543 - 0 -ELLIPSE - 5 -529 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.1208297606626161 - 20 --0.07983864518260481 - 30 -0 - 11 -0.08232881912082091 - 21 --0.08232881912082091 - 31 -0 - 40 -0.9999999999999925 - 41 -5.115386456613116 - 42 -5.714220689477993 - 0 -ELLIPSE - 5 -52A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0027469622371541 - 20 --0.1118831317344586 - 30 -0 - 11 -0.008568839601392699 - 21 --0.008568839601392699 - 31 -0 - 40 -0.99999999999972 - 41 --1.405760339110585 - 42 -2.976215721279543 - 0 -ELLIPSE - 5 -52B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.1263127525591585 - 20 --0.0797965142267003 - 30 -0 - 11 -0.0823288191207574 - 21 --0.0823288191207574 - 31 -0 - 40 -0.9999999999999531 - 41 -2.139419999873403 - 42 -2.738254232738236 - 0 -ELLIPSE - 5 -52C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.002732789985032 - 20 --0.0287479181331776 - 30 -0 - 11 --0.0122471446998237 - 21 --0.0122471446998237 - 31 -0 - 40 -0.9999999999995036 - 41 -0.3282574131555149 - 42 -4.383790622607908 - 0 -ELLIPSE - 5 -52D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.06810092985136861 - 20 --0.0263795732227266 - 30 -0 - 11 -0.0123493228681062 - 21 --0.0123493228681062 - 31 -0 - 40 -0.9999999999982275 - 41 -5.900784619497413 - 42 -6.499618852700003 - 0 -ELLIPSE - 5 -52E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0583924701011824 - 20 --0.0428856950881311 - 30 -0 - 11 -0.0012853259402043 - 21 --0.0012853259402043 - 31 -0 - 40 -0.9999999999995312 - 41 --0.6203621761784079 - 42 -3.76161388490069 - 0 -ELLIPSE - 5 -52F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.041883039136053 - 20 --0.0525885265937234 - 30 -0 - 11 --0.0123493228680959 - 21 --0.0123493228680959 - 31 -0 - 40 -0.9999999999992443 - 41 -1.354021835996382 - 42 -1.952856069332864 - 0 -ELLIPSE - 5 -530 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0495761522950602 - 20 --0.0340663708998932 - 30 -0 - 11 -0.001837071704974 - 21 --0.001837071704974 - 31 -0 - 40 -0.9999999999994207 - 41 -2.684451902837356 - 42 -6.739985112866805 - 0 -ELLIPSE - 5 -531 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0466997878237976 - 20 --0.0525893477160366 - 30 -0 - 11 -0.0123493228681223 - 21 --0.0123493228681223 - 31 -0 - 40 -0.9999999999995205 - 41 -4.329988293226125 - 42 -4.928822526562929 - 0 -ELLIPSE - 5 -532 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0301936659464559 - 20 --0.0428808879728138 - 30 -0 - 11 --0.0012853259402012 - 21 --0.0012853259402012 - 31 -0 - 40 -0.9999999999978104 - 41 --3.761954829525154 - 42 -0.6200212315576632 - 0 -ELLIPSE - 5 -533 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0204908344338151 - 20 --0.0263714570196498 - 30 -0 - 11 --0.0123493228681139 - 21 --0.0123493228681139 - 31 -0 - 40 -0.9999999999988762 - 41 --0.2167744901405007 - 42 -0.382059743061979 - 0 -ELLIPSE - 5 -534 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0390129901412024 - 20 --0.0340645701731717 - 30 -0 - 11 -0.001837071704974 - 21 --0.001837071704974 - 31 -0 - 40 -0.9999999999993807 - 41 -1.113655576489847 - 42 -5.169188786518227 - 0 -ELLIPSE - 5 -535 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.04429547158162 - 20 --0.0287838894633978 - 30 -0 - 11 -0.0057408490780452 - 21 --0.0057408490780452 - 31 -0 - 40 -0.9999999999997577 - 41 -1.895076218431659 - 42 -2.816971817239786 - 0 -ELLIPSE - 5 -536 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.04429547158162 - 20 --0.0287838894633978 - 30 -0 - 11 -0.0057408490780365 - 21 --0.0057408490780365 - 31 -0 - 40 -0.999999999999583 - 41 -5.036668872021402 - 42 -5.958564470829807 - 0 -ELLIPSE - 5 -537 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.04429547158162 - 20 --0.0287838894633978 - 30 -0 - 11 -0.0057408490780406 - 21 --0.0057408490780406 - 31 -0 - 40 -0.999999999999841 - 41 -3.465872544669369 - 42 -4.387768144676132 - 0 -ELLIPSE - 5 -538 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0204900133115302 - 20 --0.0311882057040123 - 30 -0 - 11 -0.0123493228681636 - 21 --0.0123493228681636 - 31 -0 - 40 -0.9999999999995047 - 41 -2.759191965902173 - 42 -3.358026199104234 - 0 -ELLIPSE - 5 -539 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0301984730619438 - 20 --0.0146820838385793 - 30 -0 - 11 --0.0012853259401934 - 21 --0.0012853259401934 - 31 -0 - 40 -0.9999999999976362 - 41 -0.9504341506094782 - 42 -5.332410211684042 - 0 -ELLIPSE - 5 -53A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0467079040269596 - 20 --0.0049792523330154 - 30 -0 - 11 -0.0123493228681184 - 21 --0.0123493228681184 - 31 -0 - 40 -0.9999999999983812 - 41 -6.06641081637781 - 42 -6.665245049715536 - 0 -ELLIPSE - 5 -53B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0390147908678387 - 20 --0.0235014080269025 - 30 -0 - 11 --0.0018370717049768 - 21 --0.0018370717049768 - 31 -0 - 40 -0.9999999999997335 - 41 --2.027937077547934 - 42 -2.027596132478682 - 0 -ELLIPSE - 5 -53C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0418911553391013 - 20 --0.0049784312107022 - 30 -0 - 11 --0.0123493228680869 - 21 --0.0123493228680869 - 31 -0 - 40 -0.999999999998668 - 41 --0.3824006871619128 - 42 -0.2164335461759794 - 0 -ELLIPSE - 5 -53D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0583972772165566 - 20 --0.0146868909539819 - 30 -0 - 11 --0.0012853259402012 - 21 --0.0012853259402012 - 31 -0 - 40 -0.9999999999978104 - 41 --0.6203621759353588 - 42 -3.761613885147457 - 0 -ELLIPSE - 5 -53E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0681001087291975 - 20 --0.031196321907089 - 30 -0 - 11 --0.0123493228681196 - 21 --0.0123493228681195 - 31 -0 - 40 -0.9999999999993539 - 41 -2.924818163449156 - 42 -3.523652396651432 - 0 -ELLIPSE - 5 -53F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0495779530219238 - 20 --0.0235032087535387 - 30 -0 - 11 -0.0018370717049817 - 21 --0.0018370717049817 - 31 -0 - 40 -0.9999999999990304 - 41 --2.02793707710577 - 42 -2.027596132920821 - 0 -ELLIPSE - 5 -540 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0497610515513429 - 20 --0.0287838894633978 - 30 -0 - 11 --0.0057408490780428 - 21 --0.0057408490780428 - 31 -0 - 40 -0.9999999999998058 - 41 -0.3246208357088048 - 42 -1.24651643571472 - 0 -ELLIPSE - 5 -541 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0497610515513429 - 20 --0.0287838894633978 - 30 -0 - 11 -0.0034445094468257 - 21 --0.0034445094468257 - 31 -0 - 40 -0.9999999999988096 - 41 -0.7853981633980434 - 42 -7.068583470577627 - 0 -ELLIPSE - 5 -542 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0735665098212053 - 20 --0.0263795732227266 - 30 -0 - 11 -0.0123493228681062 - 21 --0.0123493228681062 - 31 -0 - 40 -0.9999999999982275 - 41 --0.2164335455204167 - 42 -0.3824006876821728 - 0 -ELLIPSE - 5 -543 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.06385805007101911 - 20 --0.0428856950881311 - 30 -0 - 11 -0.0012853259402043 - 21 --0.0012853259402043 - 31 -0 - 40 -0.9999999999995312 - 41 -2.521571422278896 - 42 -6.903547483357994 - 0 -ELLIPSE - 5 -544 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0473486191058896 - 20 --0.0525885265937234 - 30 -0 - 11 --0.0123493228680959 - 21 --0.0123493228680959 - 31 -0 - 40 -0.999999999999244 - 41 -4.330329237846723 - 42 -4.929163471183204 - 0 -ELLIPSE - 5 -545 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0550417322647832 - 20 --0.0340663708998932 - 30 -0 - 11 -0.001837071704974 - 21 --0.001837071704974 - 31 -0 - 40 -0.9999999999994207 - 41 --0.4567998056872187 - 42 -3.59873340434223 - 0 -ELLIPSE - 5 -546 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0521653677936342 - 20 --0.0525893477160366 - 30 -0 - 11 -0.0123493228681223 - 21 --0.0123493228681223 - 31 -0 - 40 -0.9999999999995205 - 41 -1.354362780616658 - 42 -1.953197013953461 - 0 -ELLIPSE - 5 -547 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0356592459162926 - 20 --0.0428808879728138 - 30 -0 - 11 --0.0012853259402012 - 21 --0.0012853259402012 - 31 -0 - 40 -0.9999999999978104 - 41 -5.663164075621923 - 42 -10.04514013670474 - 0 -ELLIPSE - 5 -548 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0259564144036517 - 20 --0.0263714570196498 - 30 -0 - 11 --0.0123493228681139 - 21 --0.0123493228681139 - 31 -0 - 40 -0.9999999999988762 - 41 -5.901125564117607 - 42 -6.499959797320087 - 0 -ELLIPSE - 5 -549 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0444785701109254 - 20 --0.0340645701731717 - 30 -0 - 11 -0.001837071704974 - 21 --0.001837071704974 - 31 -0 - 40 -0.9999999999993807 - 41 -1.11399652066136 - 42 -5.16952973068974 - 0 -ELLIPSE - 5 -54A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0497610515513429 - 20 --0.0287838894633978 - 30 -0 - 11 -0.0057408490780452 - 21 --0.0057408490780452 - 31 -0 - 40 -0.9999999999997577 - 41 -3.4662134899398 - 42 -4.388109088747927 - 0 -ELLIPSE - 5 -54B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0497610515513429 - 20 --0.0287838894633978 - 30 -0 - 11 -0.0057408490780365 - 21 --0.0057408490780365 - 31 -0 - 40 -0.999999999999583 - 41 -0.3246208363497793 - 42 -1.246516435158184 - 0 -ELLIPSE - 5 -54C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0497610515513429 - 20 --0.0287838894633978 - 30 -0 - 11 -0.0057408490780406 - 21 --0.0057408490780406 - 31 -0 - 40 -0.999999999999841 - 41 -1.895417162503454 - 42 -2.817312762510217 - 0 -ELLIPSE - 5 -54D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0259555932812532 - 20 --0.0311882057040123 - 30 -0 - 11 -0.0123493228681636 - 21 --0.0123493228681636 - 31 -0 - 40 -0.9999999999995047 - 41 -2.925159108075352 - 42 -3.523993341277413 - 0 -ELLIPSE - 5 -54E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0356640530317805 - 20 --0.0146820838385793 - 30 -0 - 11 --0.0012853259401934 - 21 --0.0012853259401934 - 31 -0 - 40 -0.9999999999976362 - 41 -0.9507750954955444 - 42 -5.332751156570108 - 0 -ELLIPSE - 5 -54F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0521734839966825 - 20 --0.0049792523330154 - 30 -0 - 11 -0.0123493228681184 - 21 --0.0123493228681184 - 31 -0 - 40 -0.9999999999983812 - 41 --0.3820597425359502 - 42 -0.2167744908017763 - 0 -ELLIPSE - 5 -550 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0444803708376753 - 20 --0.0235014080269025 - 30 -0 - 11 --0.0018370717049768 - 21 --0.0018370717049768 - 31 -0 - 40 -0.9999999999997335 - 41 -4.255589174700904 - 42 -8.31112238472752 - 0 -ELLIPSE - 5 -551 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0473567353088242 - 20 --0.0049784312107022 - 30 -0 - 11 --0.0123493228680869 - 21 --0.0123493228680869 - 31 -0 - 40 -0.9999999999986684 - 41 -6.066751761003607 - 42 -6.665585994341499 - 0 -ELLIPSE - 5 -552 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0638628571862796 - 20 --0.0146868909539819 - 30 -0 - 11 --0.0012853259402012 - 21 --0.0012853259402012 - 31 -0 - 40 -0.9999999999978104 - 41 -2.521571422032129 - 42 -6.903547483114945 - 0 -ELLIPSE - 5 -553 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0735656886990341 - 20 --0.031196321907089 - 30 -0 - 11 --0.0123493228681196 - 21 --0.0123493228681195 - 31 -0 - 40 -0.9999999999993539 - 41 -2.759532910528154 - 42 -3.35836714373043 - 0 -ELLIPSE - 5 -554 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0550435329916468 - 20 --0.0235032087535387 - 30 -0 - 11 -0.0018370717049817 - 21 --0.0018370717049817 - 31 -0 - 40 -0.9999999999990304 - 41 -4.255589174258765 - 42 -8.311122384285357 - 0 -ENDBLK - 5 -1BC -330 -1BA -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -ENDSEC - 0 -SECTION - 2 -ENTITIES - 0 -MTEXT - 5 -555 -100 -AcDbEntity - 8 -PLAN_INFO - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3274.596016143105 - 20 -1434.320983020817 - 30 -0 - 40 -3.040537499999998 - 41 -162.4998342769979 - 71 - 4 - 72 - 5 - 3 -RS_NO=59/C11 PART,TS NO.7-7-128/2 PART\PREVENUE_WARD=7\PVILLAGE=NAGARAM\PDESAM=NAGARAM\P\PPLOT_AREA_M2=320\PDEPTH_CUTTING_MORE_THAN_1.5_M=NO\PCRZ=NO\PSECURITY_ZONE=NO\PACCESS_WIDTH_M=3.6\P\POPENING_ABOVE_2.1_ON_SIDE_LESS_1M_OR_LESS_EQUALTO_0.6M=NA - 3 - \POPENING_BELOW_2.1_ON_SIDE_LESS_1M_OR_LESS_EQUALTO_0.6M=NA\POPENING_ABOVE_2.1_ON_REAR_LESS_1M=NA\POPENING_BELOW_2.1_ON_REAR_LESS_1M=NA\PNOC_TO_ABUT_SIDE=NO\PNOC_TO_REAR_SIDE=NO\P\PWHETHER_GOVT_OR_AIDED_SCHOOL=NO\PMECHANICAL_PARKING=0\PEXISTING_FLOO - 1 -R_AREA_TO_BE_DEMOLISHED_M2=0\PPLOT_IN_COMMERCIAL_ZONE=YES - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LINE - 5 -556 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3285.131714331685 - 20 -1244.402369962656 - 11 -3285.131714331685 - 21 -1244.445176272304 - 0 -LINE - 5 -557 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3285.131714331685 - 20 -1244.48176036129 - 11 -3285.131714331685 - 21 -1244.52456667088 - 0 -LINE - 5 -558 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 52 -370 - 0 -100 -AcDbLine - 10 -3286.406714331592 - 20 -1244.402369962656 - 11 -3286.406714331592 - 21 -1243.472369962663 - 0 -LINE - 5 -559 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3286.406714331592 - 20 -1244.552369962621 - 11 -3286.254891354825 - 21 -1244.552369962621 - 0 -LINE - 5 -55A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3285.254891354823 - 20 -1244.552369962679 - 11 -3285.103068378288 - 21 -1244.552369962679 - 0 -LINE - 5 -55B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3286.406714331592 - 20 -1244.752369962633 - 11 -3286.254891354825 - 21 -1244.752369962633 - 0 -LINE - 5 -55C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3285.254891354823 - 20 -1244.752369962633 - 11 -3284.903068378103 - 21 -1244.752369962633 - 0 -LINE - 5 -55D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3285.131714331685 - 20 -1244.402369962656 - 11 -3285.131714331685 - 21 -1244.445176272304 - 0 -LINE - 5 -55E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3285.131714331685 - 20 -1244.48176036129 - 11 -3285.131714331685 - 21 -1244.52456667088 - 0 -LWPOLYLINE - 5 -55F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbPolyline - 90 - 8 - 70 - 0 - 43 -0 - 10 -3286.406714331592 - 20 -1243.472369962663 - 10 -3286.406714331592 - 20 -1244.752369962633 - 10 -3286.606714331778 - 20 -1244.752369962633 - 10 -3286.756714331686 - 20 -1244.752369962633 - 10 -3286.756714331686 - 20 -1244.522369962651 - 10 -3286.606714331778 - 20 -1244.522369962651 - 10 -3286.606714331778 - 20 -1243.472369962663 - 10 -3286.406714331592 - 20 -1243.472369962663 - 0 -LINE - 5 -560 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3289.840538748308 - 20 -1243.423737554054 - 11 -3289.840538748308 - 21 -1240.394335589313 - 0 -LINE - 5 -561 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3293.309696737097 - 20 -1241.112806992692 - 11 -3289.840538748308 - 21 -1241.110540415975 - 0 -LINE - 5 -562 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3293.075420911424 - 20 -1242.276362763427 - 11 -3289.840538748308 - 21 -1242.276362763427 - 0 -LINE - 5 -563 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1243.852369962668 - 11 -3281.603068378288 - 21 -1243.852369962668 - 0 -LINE - 5 -564 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1243.552369962679 - 11 -3281.603068378288 - 21 -1243.552369962679 - 0 -LINE - 5 -565 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1244.152369962656 - 11 -3281.603068378288 - 21 -1244.152369962656 - 0 -LINE - 5 -566 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1244.452369962644 - 11 -3281.603068378288 - 21 -1244.452369962644 - 0 -LINE - 5 -567 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1244.752369962633 - 11 -3281.603068378288 - 21 -1244.752369962633 - 0 -LINE - 5 -568 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1245.052369962679 - 11 -3281.603068378288 - 21 -1245.052369962679 - 0 -LINE - 5 -569 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1245.352369962667 - 11 -3281.603068378288 - 21 -1245.352369962667 - 0 -LINE - 5 -56A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1245.652369962656 - 11 -3281.603068378288 - 21 -1245.652369962656 - 0 -LINE - 5 -56B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1245.952369962644 - 11 -3281.603068378288 - 21 -1245.952369962644 - 0 -LINE - 5 -56C -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3283.703068378148 - 20 -1243.602689753345 - 11 -3283.703068378148 - 21 -1242.352369962667 - 0 -LINE - 5 -56D -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3283.403068378103 - 20 -1243.552369962679 - 11 -3283.403068378103 - 21 -1242.352369962667 - 0 -LINE - 5 -56E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3283.103068378288 - 20 -1243.552369962679 - 11 -3283.103068378288 - 21 -1242.352369962667 - 0 -LINE - 5 -56F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.803068378242 - 20 -1243.552369962679 - 11 -3282.803068378242 - 21 -1242.352369962667 - 0 -LINE - 5 -570 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3283.703068378148 - 20 -1243.852369962668 - 11 -3284.903068378103 - 21 -1243.852369962668 - 0 -LINE - 5 -571 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3283.703068378148 - 20 -1244.152369962656 - 11 -3284.903068378103 - 21 -1244.152369962656 - 0 -LINE - 5 -572 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3283.703068378148 - 20 -1244.452369962644 - 11 -3284.903068378103 - 21 -1244.452369962644 - 0 -LINE - 5 -573 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3283.703068378148 - 20 -1244.752369962633 - 11 -3284.903068378103 - 21 -1244.752369962633 - 0 -LINE - 5 -574 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3283.703068378148 - 20 -1245.052369962679 - 11 -3284.903068378103 - 21 -1245.052369962679 - 0 -LINE - 5 -575 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3281.853068378288 - 20 -1243.552369962679 - 11 -3283.103068378288 - 21 -1243.552369962679 - 0 -LINE - 5 -576 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3283.403068378103 - 20 -1243.552369962679 - 11 -3284.903068378103 - 21 -1243.552369962679 - 0 -LWPOLYLINE - 5 -577 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3282.802694132552 - 20 -1245.952369962644 - 10 -3282.802694132552 - 20 -1243.552369962679 - 10 -3283.103068378288 - 20 -1243.552369962679 - 0 -LWPOLYLINE - 5 -578 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3283.403068378103 - 20 -1243.552369962679 - 10 -3283.703068378148 - 20 -1243.552369962679 - 10 -3283.703068378148 - 20 -1245.052369962679 - 0 -LWPOLYLINE - 5 -579 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3282.772694132524 - 20 -1245.952369962644 - 10 -3282.772694132524 - 20 -1243.522369962651 - 10 -3283.103068378288 - 20 -1243.522369962651 - 0 -LWPOLYLINE - 5 -57A -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3283.403068378103 - 20 -1243.522369962651 - 10 -3283.733068378178 - 20 -1243.522369962651 - 10 -3283.733068378178 - 20 -1245.052369962679 - 0 -LWPOLYLINE - 5 -57B -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3282.742694132496 - 20 -1245.952369962644 - 10 -3282.742694132496 - 20 -1243.492369962681 - 10 -3283.103068378288 - 20 -1243.492369962681 - 0 -LWPOLYLINE - 5 -57C -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3283.403068378103 - 20 -1243.492369962681 - 10 -3283.763068378205 - 20 -1243.492369962681 - 10 -3283.763068378205 - 20 -1245.052369962679 - 0 -LINE - 5 -57D -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1245.952369962644 - 11 -3282.802694132552 - 21 -1244.752369962633 - 0 -LINE - 5 -57E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3284.903068378103 - 20 -1243.472369962663 - 11 -3284.903068378103 - 21 -1244.752369962633 - 0 -LINE - 5 -57F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3285.103068378288 - 20 -1243.672369962675 - 11 -3285.103068378288 - 21 -1244.552369962679 - 0 -HATCH - 5 -580 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3285.101714331658 - 20 -1242.340948482917 - 11 -3284.903068378103 - 21 -1242.300036849163 - 72 - 1 - 10 -3284.903068378103 - 20 -1242.300036849163 - 11 -3284.903068378103 - 21 -1242.154635776649 - 72 - 1 - 10 -3284.903068378103 - 20 -1242.154635776649 - 11 -3285.101714331658 - 21 -1242.154635776649 - 72 - 1 - 10 -3285.101714331658 - 20 -1242.154635776649 - 11 -3285.101714331658 - 21 -1242.340948482917 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -0.01 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -HATCH - 5 -581 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3289.840538748308 - 20 -1243.316921289777 - 11 -3289.640538748354 - 21 -1243.275730786787 - 72 - 1 - 10 -3289.640538748354 - 20 -1243.275730786787 - 11 -3289.640538748354 - 21 -1241.110540415975 - 72 - 1 - 10 -3289.640538748354 - 20 -1241.110540415975 - 11 -3289.840538748308 - 21 -1241.110540415975 - 72 - 1 - 10 -3289.840538748308 - 20 -1241.110540415975 - 11 -3289.840538748308 - 21 -1243.316921289777 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -0.01 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -HATCH - 5 -582 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3289.840538748308 - 20 -1243.423737554054 - 11 -3289.640538748354 - 21 -1243.423737554054 - 72 - 1 - 10 -3289.640538748354 - 20 -1243.423737554054 - 11 -3289.640538748354 - 21 -1243.275730786787 - 72 - 1 - 10 -3289.640538748354 - 20 -1243.275730786787 - 11 -3289.840538748308 - 21 -1243.316921289777 - 72 - 1 - 10 -3289.840538748308 - 20 -1243.316921289777 - 11 -3289.840538748308 - 21 -1243.423737554054 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -0.01 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -HATCH - 5 -583 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 2 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3291.859715389553 - 20 -1242.27636276203 - 11 -3291.859715389553 - 21 -1241.906840563519 - 72 - 1 - 10 -3291.859715389553 - 20 -1241.906840563519 - 11 -3292.459715389414 - 21 -1241.906840563519 - 72 - 1 - 10 -3292.459715389414 - 20 -1241.906840563519 - 11 -3291.859715389553 - 21 -1242.27636276203 - 97 - 0 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3291.859715389553 - 20 -1242.27636276203 - 11 -3291.25971538946 - 21 -1241.906840563519 - 72 - 1 - 10 -3291.25971538946 - 20 -1241.906840563519 - 11 -3291.859715389553 - 21 -1241.906840563519 - 72 - 1 - 10 -3291.859715389553 - 20 -1241.906840563519 - 11 -3291.859715389553 - 21 -1242.27636276203 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LINE - 5 -584 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3291.859715389553 - 20 -1239.157007771602 - 11 -3291.859715389553 - 21 -1243.114510207961 - 0 -LWPOLYLINE - 5 -585 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3292.459715389414 - 20 -1241.906840563519 - 10 -3291.25971538946 - 20 -1241.906840563519 - 10 -3291.859715389553 - 20 -1242.27636276203 - 10 -3292.459715389414 - 20 -1241.906840563519 - 0 -MTEXT - 5 -586 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3291.537871610606 - 20 -1239.259400455456 - 30 -0 - 40 -0.21 - 41 -1.160833333333376 - 71 - 1 - 72 - 5 - 1 -Ramp Dn - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -587 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3283.13231203123 - 20 -1241.401489503914 - 30 -0 - 40 -0.245 - 41 -3.035277777777835 - 71 - 1 - 72 - 5 - 1 -RCC Retaining wall - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -HATCH - 5 -588 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3281.573068378261 - 20 -1245.952369962644 - 11 -3281.373068378307 - 21 -1245.952369962644 - 72 - 1 - 10 -3281.373068378307 - 20 -1245.952369962644 - 11 -3281.373068378307 - 21 -1242.654635776649 - 72 - 1 - 10 -3281.373068378307 - 20 -1242.654635776649 - 11 -3281.573068378261 - 21 -1242.654635776649 - 72 - 1 - 10 -3281.573068378261 - 20 -1242.654635776649 - 11 -3281.573068378261 - 21 -1245.952369962644 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -0.01 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -HATCH - 5 -589 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3289.610538748326 - 20 -1243.623737554066 - 11 -3286.606714331778 - 21 -1243.623737554066 - 72 - 1 - 10 -3286.606714331778 - 20 -1243.623737554066 - 11 -3286.606714331778 - 21 -1243.423737554054 - 72 - 1 - 10 -3286.606714331778 - 20 -1243.423737554054 - 11 -3289.610538748326 - 21 -1243.423737554054 - 72 - 1 - 10 -3289.610538748326 - 20 -1243.423737554054 - 11 -3289.610538748326 - 21 -1243.623737554066 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -0.01 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -INSERT - 5 -58A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -*U4 - 10 --5510.392218238908 - 20 --1659.111589305452 - 30 -0 - 41 -0.01 - 42 -0.01 - 43 -0 - 50 -0 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -LWPOLYLINE - 5 -58B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3284.303068378243 - 20 -1243.852369962668 - 10 -3284.303068378243 - 20 -1242.952369962644 - 10 -3282.20288125542 - 20 -1242.952369962644 - 10 -3282.20288125542 - 20 -1246.164936604793 - 0 -LWPOLYLINE - 5 -58C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3284.603068378288 - 20 -1243.552369962679 - 10 -3284.003068378196 - 20 -1243.552369962679 - 10 -3284.303068378243 - 20 -1243.852369962668 - 10 -3284.603068378288 - 20 -1243.552369962679 - 0 -LEADER - 5 -58D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLeader - 3 -Standard - 71 - 1 - 72 - 0 - 73 - 3 - 74 - 0 - 75 - 0 - 40 -1 - 41 -10 - 76 -3 - 76 -3 - 10 -3282.57882252615 - 20 -1242.352369962667 - 30 -0 - 10 -3282.57882252615 - 20 -1241.332201593672 - 30 -0 - 10 -3282.957429503091 - 20 -1241.332201593672 - 30 -0 - 0 -LEADER - 5 -58E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLeader - 3 -Standard - 71 - 1 - 72 - 0 - 73 - 3 - 74 - 0 - 75 - 0 - 40 -1 - 41 -10 - 76 -3 - 76 -3 - 10 -3287.850942810532 - 20 -1243.423737554054 - 30 -0 - 10 -3287.850942810532 - 20 -1241.416164394351 - 30 -0 - 10 -3286.261099679629 - 20 -1241.416164394351 - 30 -0 - 0 -LWPOLYLINE - 5 -58F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3281.373068378307 - 20 -1245.952369962644 - 10 -3281.373068378307 - 20 -1242.154635776649 - 10 -3285.101714331658 - 20 -1242.154635776649 - 10 -3285.101714331658 - 20 -1243.472369962663 - 0 -LWPOLYLINE - 5 -590 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3281.573068378261 - 20 -1245.952369962644 - 10 -3281.573067692857 - 20 -1242.352978129291 - 10 -3284.903068378103 - 20 -1242.351769962667 - 10 -3284.901714331704 - 20 -1243.472369962663 - 0 -LWPOLYLINE - 5 -591 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3286.406714331592 - 20 -1243.472369962663 - 10 -3286.406714331592 - 20 -1242.922369962616 - 10 -3285.101714331658 - 20 -1242.922369962616 - 0 -LWPOLYLINE - 5 -592 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3286.606714331778 - 20 -1243.472369962663 - 10 -3286.606714331778 - 20 -1242.722369962663 - 10 -3285.101714331658 - 20 -1242.722369962663 - 0 -HATCH - 5 -593 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 6 - 72 - 1 - 10 -3286.606714331778 - 20 -1243.423737554054 - 11 -3286.406714331825 - 21 -1243.423737554054 - 72 - 1 - 10 -3286.406714331592 - 20 -1243.423737554054 - 11 -3286.406714331592 - 21 -1242.922369962616 - 72 - 1 - 10 -3286.406714331592 - 20 -1242.922369962616 - 11 -3285.101714331658 - 21 -1242.922369962616 - 72 - 1 - 10 -3285.101714331658 - 20 -1242.922369962616 - 11 -3285.101714331658 - 21 -1242.722369962605 - 72 - 1 - 10 -3285.101714331658 - 20 -1242.722369962663 - 11 -3286.606714331545 - 21 -1242.722369962663 - 72 - 1 - 10 -3286.606714331778 - 20 -1242.722369962663 - 11 -3286.606714331778 - 21 -1243.423737554112 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -0.01 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -LWPOLYLINE - 5 -594 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3285.101714331658 - 20 -1243.472369962663 - 10 -3284.903068378103 - 20 -1243.472369962663 - 10 -3284.903068378103 - 20 -1242.352369962667 - 10 -3284.903068378103 - 20 -1242.154635776649 - 0 -HATCH - 5 -595 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 5 - 72 - 1 - 10 -3285.101714331658 - 20 -1243.423737554054 - 11 -3284.903068378103 - 21 -1243.423737554054 - 72 - 1 - 10 -3284.903068378103 - 20 -1243.423737554054 - 11 -3284.903068378103 - 21 -1242.352369962609 - 72 - 1 - 10 -3284.903068378103 - 20 -1242.352369962667 - 11 -3284.903068378103 - 21 -1242.300036849221 - 72 - 1 - 10 -3284.903068378103 - 20 -1242.300036849163 - 11 -3285.101714331658 - 21 -1242.340948482859 - 72 - 1 - 10 -3285.101714331658 - 20 -1242.340948482917 - 11 -3285.101714331658 - 21 -1243.423737554054 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -0.01 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -HATCH - 5 -596 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3284.90308648541 - 20 -1242.352438598078 - 11 -3284.197075190956 - 21 -1242.154635776649 - 72 - 1 - 10 -3284.197075190956 - 20 -1242.154635776649 - 11 -3284.903068378103 - 21 -1242.154635776649 - 72 - 1 - 10 -3284.903068378103 - 20 -1242.154635776649 - 11 -3284.90308648541 - 21 -1242.352438598078 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -0.01 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -LINE - 5 -597 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3285.254891354823 - 20 -1244.552369962679 - 11 -3285.254891354823 - 21 -1244.752369962633 - 0 -LINE - 5 -598 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3286.254891354825 - 20 -1244.552369962621 - 11 -3286.254891354825 - 21 -1244.752369962633 - 0 -LWPOLYLINE - 5 -599 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 7 - 70 - 0 - 43 -0 - 10 -3285.131714331685 - 20 -1244.552369962679 - 10 -3286.406714331592 - 20 -1244.552369962679 - 10 -3286.406714331592 - 20 -1242.922369962616 - 10 -3285.101714331658 - 20 -1242.922369962616 - 10 -3285.101714331658 - 20 -1244.252369962632 - 10 -3285.131714331685 - 20 -1244.252369962632 - 10 -3285.131714331685 - 20 -1244.552369962679 - 0 -LWPOLYLINE - 5 -59A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 1 - 43 -0 - 10 -3285.181714331731 - 20 -1244.502369962632 - 10 -3286.356714331778 - 20 -1244.502369962632 - 10 -3286.356714331778 - 20 -1242.972369962663 - 10 -3285.151714331703 - 20 -1242.972369962663 - 10 -3285.151714331703 - 20 -1244.202369962644 - 10 -3285.181714331731 - 20 -1244.202369962644 - 0 -LWPOLYLINE - 5 -59B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 1 - 43 -0 - 10 -3285.231714331778 - 20 -1244.452369962644 - 10 -3286.306714331731 - 20 -1244.452369962644 - 10 -3286.306714331731 - 20 -1243.022369962651 - 10 -3285.20171433175 - 20 -1243.022369962651 - 10 -3285.20171433175 - 20 -1244.152369962656 - 10 -3285.231714331778 - 20 -1244.152369962656 - 0 -LINE - 5 -59C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3285.131714331685 - 20 -1244.552369962679 - 11 -3286.406714331592 - 21 -1242.922369962616 - 0 -LINE - 5 -59D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3286.406714331592 - 20 -1244.552369962679 - 11 -3285.101714331658 - 21 -1242.922369962616 - 0 -LWPOLYLINE - 5 -59E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3289.610538748326 - 20 -1243.423737554054 - 10 -3286.606714331778 - 20 -1243.423737554054 - 0 -LWPOLYLINE - 5 -59F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3289.610538748326 - 20 -1243.623737554066 - 10 -3286.606714331778 - 20 -1243.623737554066 - 0 -MTEXT - 5 -5A0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3285.410073219799 - 20 -1243.275681681291 - 30 -0 - 40 -0.21 - 41 -0.5133333333333333 - 71 - 1 - 72 - 5 - 1 -LIFT - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -5A1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3285.779215662741 - 20 -1243.303355389158 - 30 -0 - 40 -0.21 - 41 -1.026666666666706 - 71 - 1 - 72 - 5 - 1 -163X130 - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -5A2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3283.059859681409 - 20 -1239.929147053685 - 30 -0 - 40 -0.245 - 41 -2.361527777777777 - 71 - 1 - 72 - 5 - 1 -EARTH FILLING - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -5A3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3281.373068378307 - 20 -1246.452369962644 - 10 -3281.373068378307 - 20 -1259.280104148725 - 10 -3293.070538748289 - 20 -1259.280104148725 - 10 -3293.070538748289 - 20 -1245.952369962644 - 0 -LWPOLYLINE - 5 -5A4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3281.373068378307 - 20 -1246.452369962644 - 10 -3281.373068378182 - 20 -1259.280104148725 - 10 -3293.070538748289 - 20 -1259.280104148715 - 10 -3293.070538748289 - 20 -1245.952369963459 - 0 -MTEXT - 5 -5A5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3281.878084598111 - 20 -1246.088766773348 - 30 -0 - 40 -0.21 - 41 -0.3033333333333333 - 71 - 1 - 72 - 5 - 1 -UP - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -LINE - 5 -5A6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3293.37053874368 - 20 -1245.952369963459 - 11 -3293.070538746659 - 21 -1245.952369963459 - 0 -LWPOLYLINE - 5 -5A7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3289.840538748308 - 20 -1243.423737554054 - 10 -3289.840538748308 - 20 -1241.110540415975 - 10 -3289.640538748354 - 20 -1241.110540415975 - 10 -3289.640538748354 - 20 -1243.423737554054 - 0 -MTEXT - 5 -5A8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3285.859977117814 - 20 -1250.68617734451 - 30 -0 - 40 -0.4900000000000003 - 41 -4.831944444444448 - 71 - 1 - 72 - 5 - 1 -PARKING AREA - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883194 - 73 - 1 - 44 -1 - 0 -DIMENSION - 5 -5A9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D3 - 10 -3288.623488413138 - 20 -1259.280104148725 - 30 -0 - 11 -3288.495964981269 - 21 -1251.451920851396 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3287.835900044962 - 23 -1243.623737554066 - 33 -0 - 14 -3287.835900044962 - 24 -1259.280104148725 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -5AA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D4 - 10 -3293.070538748289 - 20 -1257.052749413065 - 30 -0 - 11 -3287.221803563298 - 21 -1257.180272844932 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3281.373068378307 - 23 -1258.780104148725 - 33 -0 - 14 -3293.070538748289 - 24 -1259.050104148744 - 34 -0 -100 -AcDbRotatedDimension - 0 -LINE - 5 -5AB -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3284.901714331704 - 20 -1244.752369962633 - 11 -3284.903068378103 - 21 -1245.052369962679 - 0 -LINE - 5 -5AC -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.081203917508 - 20 -1240.067414091609 - 11 -3282.081203917508 - 21 -1260.721494616649 - 0 -CIRCLE - 5 -5AD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3282.081203917508 - 20 -1241.147899744741 - 40 -0.3105759447062155 - 0 -HATCH - 5 -5AE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3282.391779863741 - 20 -1241.147899743053 - 11 -3282.081203918905 - 21 -1241.458475687716 - 72 - 1 - 10 -3282.081203918905 - 20 -1241.458475687716 - 11 -3282.081203918905 - 21 -1240.837323798332 - 72 - 1 - 10 -3282.081203918905 - 20 -1240.837323798332 - 11 -3282.391779863741 - 21 -1241.147899743053 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -5AF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3282.081203917508 - 20 -1240.837323805026 - 10 -3282.391779859085 - 20 -1241.147899746604 - 10 -3282.081203917508 - 20 -1241.458475688181 - 10 -3282.081203917508 - 20 -1240.837323805026 - 0 -MTEXT - 5 -5B0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3282.367171005579 - 20 -1241.193436495552 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -CIRCLE - 5 -5B1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3282.081203917508 - 20 -1260.305064083717 - 40 -0.3105759447062155 - 0 -HATCH - 5 -5B2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3282.391779863741 - 20 -1260.305064084648 - 11 -3282.081203918905 - 21 -1260.615640029369 - 72 - 1 - 10 -3282.081203918905 - 20 -1260.615640029369 - 11 -3282.081203918905 - 21 -1259.994488139928 - 72 - 1 - 10 -3282.081203918905 - 20 -1259.994488139928 - 11 -3282.391779863741 - 21 -1260.305064084648 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -5B3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3282.081203917508 - 20 -1259.994488144002 - 10 -3282.391779859085 - 20 -1260.30506408558 - 10 -3282.081203917508 - 20 -1260.615640027157 - 10 -3282.081203917508 - 20 -1259.994488144002 - 0 -MTEXT - 5 -5B4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3282.367171005579 - 20 -1260.350600837148 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LINE - 5 -5B5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3293.070538746659 - 20 -1245.952369963459 - 11 -3293.075420911424 - 21 -1242.276362763427 - 0 -LINE - 5 -5B6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3293.075420911424 - 20 -1242.276362763427 - 11 -3293.299102444435 - 21 -1241.110540415975 - 0 -LWPOLYLINE - 5 -5B7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3300.624476717086 - 20 -1259.280104148725 - 10 -3300.774476717226 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -5B8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3301.974476717179 - 20 -1259.280104148725 - 10 -3302.774476717227 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -5B9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3303.708122670651 - 20 -1259.280104148725 - 10 -3310.491947087228 - 20 -1259.280104148725 - 10 -3310.491947087228 - 20 -1245.952385825629 - 0 -LINE - 5 -5BA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3298.794476717245 - 20 -1243.321229862398 - 11 -3298.794476717245 - 21 -1256.050104161259 - 0 -LINE - 5 -5BB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1243.321229862398 - 11 -3299.024476717227 - 21 -1256.050104161259 - 0 -LINE - 5 -5BC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3301.974476717179 - 20 -1259.050104148744 - 11 -3302.774476717227 - 21 -1259.050104148744 - 0 -LINE - 5 -5BD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3303.708122670651 - 20 -1259.050104148744 - 11 -3310.261947087246 - 21 -1259.050104148744 - 0 -LINE - 5 -5BE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3310.261947087246 - 20 -1259.050104148744 - 11 -3310.261947087246 - 21 -1245.952385825629 - 0 -LINE - 5 -5BF -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1242.252369962632 - 11 -3302.304476717254 - 21 -1242.252369962632 - 0 -LINE - 5 -5C0 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3307.0319470861 - 20 -1243.423737553589 - 11 -3304.028122673277 - 21 -1243.423737553589 - 0 -LINE - 5 -5C1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3305.8319470861 - 20 -1243.123737554066 - 11 -3304.028122670717 - 21 -1243.123737554066 - 0 -LINE - 5 -5C2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3305.8319470861 - 20 -1242.823737554077 - 11 -3304.028122670717 - 21 -1242.823737554077 - 0 -LINE - 5 -5C3 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3307.031947087264 - 20 -1243.423737554054 - 11 -3307.031947087264 - 21 -1242.823737554077 - 0 -LWPOLYLINE - 5 -5C4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3298.794476717245 - 20 -1243.321229862398 - 10 -3298.794476717245 - 20 -1241.721707735967 - 10 -3298.794476717245 - 20 -1241.721707735967 - 10 -3299.024476717227 - 20 -1241.721707735967 - 10 -3299.024476717227 - 20 -1243.321229862398 - 0 -LWPOLYLINE - 5 -5C5 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3300.624476717086 - 20 -1259.280104148725 - 10 -3300.774476717226 - 20 -1259.280104148725 - 0 -LINE - 5 -5C6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.224476717179 - 20 -1243.552369962679 - 11 -3300.224476717179 - 21 -1242.352369962667 - 0 -LINE - 5 -5C7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1243.852369962668 - 11 -3302.324476717273 - 21 -1243.852369962668 - 0 -LINE - 5 -5C8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1244.152369962656 - 11 -3302.324476717273 - 21 -1244.152369962656 - 0 -LINE - 5 -5C9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1244.452369962644 - 11 -3302.324476717273 - 21 -1244.452369962644 - 0 -LINE - 5 -5CA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1244.752369962633 - 11 -3302.324476717273 - 21 -1244.752369962633 - 0 -LINE - 5 -5CB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.274476717226 - 20 -1243.552369962679 - 11 -3302.324476717273 - 21 -1243.552369962679 - 0 -LWPOLYLINE - 5 -5CC -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3300.22410247149 - 20 -1247.752369962632 - 10 -3300.22410247149 - 20 -1244.152369962656 - 0 -LWPOLYLINE - 5 -5CD -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3300.22410247149 - 20 -1243.852369962668 - 10 -3300.22410247149 - 20 -1243.552369962679 - 10 -3301.124476717087 - 20 -1243.552369962679 - 10 -3301.124476717087 - 20 -1245.052369962679 - 0 -LWPOLYLINE - 5 -5CE -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3301.124476717087 - 20 -1245.152369962656 - 10 -3301.124476717087 - 20 -1245.652369962656 - 0 -LINE - 5 -5CF -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3300.194102471462 - 20 -1247.752369962632 - 11 -3300.194102471462 - 21 -1244.152369962656 - 0 -LINE - 5 -5D0 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3300.194102471462 - 20 -1243.852369962668 - 11 -3300.194102471462 - 21 -1243.522369962651 - 0 -LINE - 5 -5D1 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3300.194102471462 - 20 -1243.522369962651 - 11 -3301.154476717115 - 21 -1243.522369962651 - 0 -LINE - 5 -5D2 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.154476717115 - 20 -1245.052369962679 - 11 -3301.154476717115 - 21 -1245.652369962656 - 0 -LINE - 5 -5D3 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3300.164102471434 - 20 -1247.752369962632 - 11 -3300.164102471434 - 21 -1244.152369962656 - 0 -LINE - 5 -5D4 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3300.164102471434 - 20 -1243.852369962668 - 11 -3300.164102471434 - 21 -1243.492369962681 - 0 -LINE - 5 -5D5 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3300.164102471434 - 20 -1243.492369962681 - 11 -3301.184476717143 - 21 -1243.492369962681 - 0 -LINE - 5 -5D6 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.184476717143 - 20 -1245.052369962679 - 11 -3301.184476717143 - 21 -1245.652369962656 - 0 -LINE - 5 -5D7 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1247.752369962632 - 11 -3300.22410247149 - 21 -1244.752369962633 - 0 -LINE - 5 -5D8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3302.324476717273 - 20 -1244.752369962633 - 11 -3302.324476717273 - 21 -1245.052369962679 - 0 -LINE - 5 -5D9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1243.852369962668 - 11 -3299.024476717227 - 21 -1243.852369962668 - 0 -LINE - 5 -5DA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1243.552369962679 - 11 -3299.024476717227 - 21 -1243.552369962679 - 0 -LINE - 5 -5DB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1244.152369962656 - 11 -3299.024476717227 - 21 -1244.152369962656 - 0 -LINE - 5 -5DC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1244.452369962644 - 11 -3299.024476717227 - 21 -1244.452369962644 - 0 -LINE - 5 -5DD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1244.752369962633 - 11 -3299.024476717227 - 21 -1244.752369962633 - 0 -LINE - 5 -5DE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1245.052369962679 - 11 -3299.024476717227 - 21 -1245.052369962679 - 0 -LINE - 5 -5DF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1245.352369962667 - 11 -3299.024476717227 - 21 -1245.352369962667 - 0 -LINE - 5 -5E0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1245.652369962656 - 11 -3299.024476717227 - 21 -1245.652369962656 - 0 -LINE - 5 -5E1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1245.952369962644 - 11 -3299.024476717227 - 21 -1245.952369962644 - 0 -LINE - 5 -5E2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1246.252369962633 - 11 -3299.024476717227 - 21 -1246.252369962633 - 0 -LINE - 5 -5E3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1246.552369962679 - 11 -3299.024476717227 - 21 -1246.552369962679 - 0 -LINE - 5 -5E4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1246.852369962667 - 11 -3299.024476717227 - 21 -1246.852369962667 - 0 -LINE - 5 -5E5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1247.152369962656 - 11 -3299.024476717227 - 21 -1247.152369962656 - 0 -LINE - 5 -5E6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1247.452369962644 - 11 -3299.024476717227 - 21 -1247.452369962644 - 0 -LINE - 5 -5E7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1247.752369962632 - 11 -3299.024476717227 - 21 -1247.752369962632 - 0 -LINE - 5 -5E8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1243.602689753345 - 11 -3301.124476717087 - 21 -1242.352369962667 - 0 -LINE - 5 -5E9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.824476717273 - 20 -1243.552369962679 - 11 -3300.824476717273 - 21 -1242.352369962667 - 0 -LINE - 5 -5EA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.524476717227 - 20 -1243.552369962679 - 11 -3300.524476717227 - 21 -1242.352369962667 - 0 -LINE - 5 -5EB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3310.261947087246 - 20 -1245.952385825629 - 11 -3310.493458622135 - 21 -1245.952369962644 - 0 -LWPOLYLINE - 5 -5EC -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3299.024476717227 - 20 -1242.352369962726 - 10 -3302.354476717068 - 20 -1242.352369962726 - 10 -3302.354476717068 - 20 -1242.722369962663 - 0 -LWPOLYLINE - 5 -5ED -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3299.024476717227 - 20 -1242.302369962737 - 10 -3302.404476717115 - 20 -1242.302369962737 - 10 -3302.404476717115 - 20 -1242.722369962663 - 0 -LWPOLYLINE - 5 -5EE -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3299.024476717227 - 20 -1242.252369962749 - 10 -3302.454476717161 - 20 -1242.252369962749 - 10 -3302.454476717161 - 20 -1242.722369962663 - 0 -LINE - 5 -5EF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1245.052369962737 - 11 -3302.324476717273 - 21 -1245.052369962679 - 0 -LINE - 5 -5F0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1245.352369962667 - 11 -3302.324476717273 - 21 -1245.352369962667 - 0 -LINE - 5 -5F1 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1245.652369962656 - 11 -3302.324476717273 - 21 -1245.652369962656 - 0 -LWPOLYLINE - 5 -5F2 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3307.031947087264 - 20 -1243.823737554077 - 10 -3310.491947087228 - 20 -1243.823737554077 - 10 -3310.491947087228 - 20 -1245.238323131343 - 0 -LWPOLYLINE - 5 -5F3 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3307.031947087264 - 20 -1243.873737554066 - 10 -3310.441947087181 - 20 -1243.873737554066 - 10 -3310.441947087181 - 20 -1245.238323131343 - 0 -LWPOLYLINE - 5 -5F4 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3307.031947087264 - 20 -1243.923737554054 - 10 -3310.391947087366 - 20 -1243.923737554054 - 10 -3310.391947087366 - 20 -1245.238323131343 - 0 -LWPOLYLINE - 5 -5F5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3310.493458622135 - 20 -1245.952369962644 - 10 -3310.491947087228 - 20 -1245.238323131343 - 10 -3310.261947087246 - 20 -1245.238323131343 - 10 -3310.261947087246 - 20 -1245.952385825629 - 0 -LINE - 5 -5F6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3302.553122670623 - 20 -1244.402369962656 - 11 -3302.553122670623 - 21 -1244.445176272304 - 0 -LINE - 5 -5F7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3302.553122670623 - 20 -1244.48176036129 - 11 -3302.553122670623 - 21 -1244.52456667088 - 0 -LINE - 5 -5F8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 52 -370 - 0 -100 -AcDbLine - 10 -3303.828122670763 - 20 -1244.402369962656 - 11 -3303.828122670763 - 21 -1243.472369962663 - 0 -LINE - 5 -5F9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3303.828122670763 - 20 -1244.552369962621 - 11 -3303.676299693994 - 21 -1244.552369962621 - 0 -LINE - 5 -5FA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3302.676299693994 - 20 -1244.552369962679 - 11 -3302.553122670623 - 21 -1244.552369962679 - 0 -LINE - 5 -5FB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3303.828122670763 - 20 -1244.752369962633 - 11 -3303.676299693994 - 21 -1244.752369962633 - 0 -LINE - 5 -5FC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3302.676299693994 - 20 -1244.752369962633 - 11 -3302.324476717273 - 21 -1244.752369962633 - 0 -LINE - 5 -5FD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3302.553122670623 - 20 -1244.402369962656 - 11 -3302.553122670623 - 21 -1244.445176272304 - 0 -LINE - 5 -5FE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3302.553122670623 - 20 -1244.48176036129 - 11 -3302.553122670623 - 21 -1244.52456667088 - 0 -LWPOLYLINE - 5 -5FF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 0 - 43 -0 - 10 -3303.828122670763 - 20 -1243.472369962663 - 10 -3303.828122670763 - 20 -1244.752369962633 - 10 -3304.028122670717 - 20 -1244.752369962633 - 10 -3304.178122670623 - 20 -1244.752369962633 - 10 -3304.178122670623 - 20 -1244.522369962651 - 10 -3304.028122670717 - 20 -1244.522369962651 - 10 -3304.028122670717 - 20 -1243.472369962663 - 10 -3303.828122670763 - 20 -1243.472369962663 - 0 -LINE - 5 -600 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3302.324476717273 - 20 -1243.472369962663 - 11 -3302.324476717273 - 21 -1244.752369962633 - 0 -LINE - 5 -601 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3302.524476717226 - 20 -1243.672369962675 - 11 -3302.524476717226 - 21 -1244.252369962632 - 0 -LWPOLYLINE - 5 -602 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3303.828122670763 - 20 -1243.472369962663 - 10 -3303.828122670763 - 20 -1242.922369962616 - 10 -3302.523122670595 - 20 -1242.922369962616 - 0 -LWPOLYLINE - 5 -603 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3304.028122670717 - 20 -1243.472369962663 - 10 -3304.028122670717 - 20 -1242.722369962663 - 10 -3302.523122670595 - 20 -1242.722369962663 - 0 -LWPOLYLINE - 5 -604 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3303.978122670669 - 20 -1243.472369962663 - 10 -3303.978122670669 - 20 -1242.772369962651 - 10 -3302.523122670595 - 20 -1242.772369962651 - 0 -LWPOLYLINE - 5 -605 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3303.928122670622 - 20 -1243.472369962663 - 10 -3303.928122670622 - 20 -1242.822369962639 - 10 -3302.523122670595 - 20 -1242.822369962639 - 0 -LWPOLYLINE - 5 -606 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3302.523122670595 - 20 -1243.472369962663 - 10 -3302.324476717273 - 20 -1243.472369962663 - 10 -3302.324476717273 - 20 -1242.722369962663 - 10 -3302.324476717273 - 20 -1242.722369962663 - 0 -LINE - 5 -607 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3302.676299693994 - 20 -1244.552369962679 - 11 -3302.676299693994 - 21 -1244.752369962633 - 0 -LINE - 5 -608 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3303.676299693994 - 20 -1244.552369962621 - 11 -3303.676299693994 - 21 -1244.752369962633 - 0 -LWPOLYLINE - 5 -609 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 7 - 70 - 0 - 43 -0 - 10 -3302.553122670623 - 20 -1244.552369962679 - 10 -3303.828122670763 - 20 -1244.552369962679 - 10 -3303.828122670763 - 20 -1242.922369962616 - 10 -3302.523122670595 - 20 -1242.922369962616 - 10 -3302.523122670595 - 20 -1244.252369962632 - 10 -3302.553122670623 - 20 -1244.252369962632 - 10 -3302.553122670623 - 20 -1244.552369962679 - 0 -LWPOLYLINE - 5 -60A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 1 - 43 -0 - 10 -3302.60312267067 - 20 -1244.502369962632 - 10 -3303.778122670716 - 20 -1244.502369962632 - 10 -3303.778122670716 - 20 -1242.972369962663 - 10 -3302.57312267064 - 20 -1242.972369962663 - 10 -3302.57312267064 - 20 -1244.202369962644 - 10 -3302.60312267067 - 20 -1244.202369962644 - 0 -LWPOLYLINE - 5 -60B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 1 - 43 -0 - 10 -3302.653122670716 - 20 -1244.452369962644 - 10 -3303.728122670669 - 20 -1244.452369962644 - 10 -3303.728122670669 - 20 -1243.022369962651 - 10 -3302.623122670688 - 20 -1243.022369962651 - 10 -3302.623122670688 - 20 -1244.152369962656 - 10 -3302.653122670716 - 20 -1244.152369962656 - 0 -LINE - 5 -60C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3302.553122670623 - 20 -1244.552369962679 - 11 -3303.828122670763 - 21 -1242.922369962616 - 0 -LINE - 5 -60D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3303.828122670763 - 20 -1244.552369962679 - 11 -3302.523122670595 - 21 -1242.922369962616 - 0 -MTEXT - 5 -60E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3302.83148155897 - 20 -1243.275681681291 - 30 -0 - 40 -0.21 - 41 -0.5133333333333333 - 71 - 1 - 72 - 5 - 1 -LIFT - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -60F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3303.200624001679 - 20 -1243.303355389158 - 30 -0 - 40 -0.21 - 41 -1.026666666666706 - 71 - 1 - 72 - 5 - 1 -163X130 - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -LINE - 5 -610 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3302.323122670641 - 20 -1244.752369962633 - 11 -3302.324476717273 - 21 -1245.052369962679 - 0 -LWPOLYLINE - 5 -611 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3302.523122670595 - 20 -1243.423737554054 - 10 -3302.523122670595 - 20 -1242.722369962663 - 10 -3302.324476717273 - 20 -1242.722369962663 - 10 -3302.324476717273 - 20 -1243.423737554054 - 0 -HATCH - 5 -612 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3299.624509939226 - 20 -1243.852369962668 - 11 -3299.624730284093 - 21 -1243.552369962679 - 72 - 1 - 10 -3299.624730284093 - 20 -1243.552369962679 - 11 -3299.928648714209 - 21 -1243.552369962679 - 72 - 1 - 10 -3299.928648714209 - 20 -1243.552369962679 - 11 -3299.624509939226 - 21 -1243.852369962668 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -613 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3299.624509939226 - 20 -1243.852369962668 - 11 -3299.339834515239 - 21 -1243.552369962679 - 72 - 1 - 10 -3299.339834515239 - 20 -1243.552369962679 - 11 -3299.624730284093 - 21 -1243.552369962679 - 72 - 1 - 10 -3299.624730284093 - 20 -1243.552369962679 - 11 -3299.624509939226 - 21 -1243.852369962668 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -614 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3301.738169059623 - 20 -1246.567925359879 - 10 -3301.738169059623 - 20 -1243.552369962679 - 10 -3301.738169059623 - 20 -1242.922737527056 - 10 -3299.625192738371 - 20 -1242.922737527056 - 10 -3299.624289594358 - 20 -1244.152369962656 - 0 -LWPOLYLINE - 5 -615 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3299.928648714209 - 20 -1243.552369962679 - 10 -3299.624509939226 - 20 -1243.852369962668 - 10 -3299.339834515239 - 20 -1243.552369962679 - 10 -3299.928648714209 - 20 -1243.552369962679 - 0 -LWPOLYLINE - 5 -616 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3301.154476717115 - 20 -1243.82236996438 - 10 -3301.154476717115 - 20 -1245.402369964397 - 10 -3300.194102471462 - 20 -1245.402369964397 - 0 -LWPOLYLINE - 5 -617 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3301.184476717143 - 20 -1243.792369964411 - 10 -3301.184476717143 - 20 -1245.452369964385 - 10 -3300.194102471462 - 20 -1245.452369964385 - 0 -LINE - 5 -618 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3302.324476717273 - 20 -1245.052369962679 - 11 -3302.324476717273 - 21 -1245.652369962656 - 0 -LWPOLYLINE - 5 -619 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3302.323122670641 - 20 -1244.752369962633 - 10 -3302.324476717273 - 20 -1245.052369962679 - 0 -LWPOLYLINE - 5 -61A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3302.373122161487 - 20 -1244.752144290542 - 10 -3302.374476207886 - 20 -1245.05214429053 - 0 -LWPOLYLINE - 5 -61B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3302.4231216521 - 20 -1244.751918618393 - 10 -3302.424475698499 - 20 -1245.051918618439 - 0 -LWPOLYLINE - 5 -61C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3302.324476717273 - 20 -1245.052369962679 - 10 -3302.424475698499 - 20 -1245.051918618439 - 0 -LINE - 5 -61D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1256.300104148744 - 11 -3299.774476717227 - 21 -1256.300104148744 - 0 -LINE - 5 -61E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1256.500104148697 - 11 -3299.774476717227 - 21 -1256.500104148697 - 0 -LINE - 5 -61F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1256.700104148709 - 11 -3299.774476717227 - 21 -1256.700104148709 - 0 -LINE - 5 -620 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1256.900104148721 - 11 -3299.774476717227 - 21 -1256.900104148721 - 0 -LINE - 5 -621 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1257.100104148732 - 11 -3299.774476717227 - 21 -1257.100104148732 - 0 -LINE - 5 -622 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1257.300104148744 - 11 -3299.774476717227 - 21 -1257.300104148744 - 0 -LINE - 5 -623 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1257.500104148697 - 11 -3299.774476717227 - 21 -1257.500104148697 - 0 -LINE - 5 -624 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1257.700104148709 - 11 -3299.774476717227 - 21 -1257.700104148709 - 0 -LINE - 5 -625 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1257.900104148721 - 11 -3299.774476717227 - 21 -1257.900104148721 - 0 -LINE - 5 -626 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1258.100104148732 - 11 -3299.774476717227 - 21 -1258.100104148732 - 0 -LINE - 5 -627 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1258.300104148744 - 11 -3299.774476717227 - 21 -1258.300104148744 - 0 -LWPOLYLINE - 5 -628 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3299.774476717227 - 20 -1258.300104148744 - 10 -3299.774476717227 - 20 -1258.100104148732 - 0 -LWPOLYLINE - 5 -629 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3299.774476717227 - 20 -1257.900104148721 - 10 -3299.774476717227 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -62A -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3299.874476717086 - 20 -1258.300104148744 - 10 -3299.874476717086 - 20 -1256.300104148744 - 0 -LINE - 5 -62B -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1256.300104148744 - 11 -3300.624476717086 - 21 -1256.300104148744 - 0 -LINE - 5 -62C -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1256.500104148697 - 11 -3300.624476717086 - 21 -1256.500104148697 - 0 -LINE - 5 -62D -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1256.700104148709 - 11 -3300.624476717086 - 21 -1256.700104148709 - 0 -LINE - 5 -62E -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1256.900104148721 - 11 -3300.624476717086 - 21 -1256.900104148721 - 0 -LINE - 5 -62F -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1257.100104148732 - 11 -3300.624476717086 - 21 -1257.100104148732 - 0 -LINE - 5 -630 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1257.300104148744 - 11 -3300.624476717086 - 21 -1257.300104148744 - 0 -LINE - 5 -631 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1257.500104148697 - 11 -3300.624476717086 - 21 -1257.500104148697 - 0 -LINE - 5 -632 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476703351 - 20 -1257.700104148767 - 11 -3300.624476733152 - 21 -1257.700104148767 - 0 -LINE - 5 -633 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1257.900104148721 - 11 -3300.624476717086 - 21 -1257.900104148721 - 0 -LINE - 5 -634 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1258.100104148732 - 11 -3300.624476717086 - 21 -1258.100104148732 - 0 -LINE - 5 -635 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1258.300104148744 - 11 -3300.624476717086 - 21 -1258.300104148744 - 0 -LWPOLYLINE - 5 -636 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3300.624476717086 - 20 -1259.050104148744 - 10 -3300.624476717086 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -637 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3299.774476717227 - 20 -1256.300104148744 - 10 -3299.774476717227 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -638 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3299.774476717227 - 20 -1258.100104148732 - 10 -3299.774476717227 - 20 -1258.300104148744 - 10 -3299.874476717086 - 20 -1258.300104148744 - 10 -3299.874476717086 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -639 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3299.744476717199 - 20 -1256.300104148744 - 10 -3299.744476717199 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -63A -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3299.744476717199 - 20 -1258.100104148732 - 10 -3299.744476717199 - 20 -1258.330104148714 - 10 -3299.904476717114 - 20 -1258.330104148714 - 10 -3299.904476717114 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -63B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3299.71447671717 - 20 -1256.300104148744 - 10 -3299.71447671717 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -63C -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3299.71447671717 - 20 -1258.100104148732 - 10 -3299.71447671717 - 20 -1258.360104148741 - 10 -3299.934476717143 - 20 -1258.360104148741 - 10 -3299.934476717143 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -63D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3300.624476717086 - 20 -1255.998735667439 - 10 -3300.624476717086 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -63E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3300.774476717226 - 20 -1256.048921864945 - 10 -3300.774476717226 - 20 -1259.050104148744 - 0 -LWPOLYLINE - 5 -63F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3300.774476717226 - 20 -1257.550104148744 - 10 -3301.074575636537 - 20 -1257.550104148744 - 0 -LWPOLYLINE - 5 -640 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3300.774476717226 - 20 -1257.550104148744 - 10 -3301.824485586723 - 20 -1257.550104148744 - 0 -LWPOLYLINE - 5 -641 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3302.724476717179 - 20 -1257.550104148744 - 10 -3302.724476717179 - 20 -1259.050104148744 - 0 -LWPOLYLINE - 5 -642 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3300.774476716761 - 20 -1257.500104145787 - 10 -3301.824476721231 - 20 -1257.500104145787 - 0 -LWPOLYLINE - 5 -643 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3302.724476717179 - 20 -1257.500104148697 - 10 -3302.774476717227 - 20 -1257.500104148697 - 10 -3302.774476717227 - 20 -1259.050104148744 - 0 -LINE - 5 -644 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3303.94001641986 - 20 -1256.048360379122 - 11 -3303.94001641986 - 21 -1259.050104148744 - 0 -LINE - 5 -645 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3303.840016419767 - 20 -1256.048360379122 - 11 -3303.840016419767 - 21 -1259.050104148744 - 0 -LWPOLYLINE - 5 -646 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3303.574476713782 - 20 -1257.500104145787 - 10 -3303.840016419535 - 20 -1257.500104145787 - 0 -LWPOLYLINE - 5 -647 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3303.574476717273 - 20 -1257.550104148744 - 10 -3303.840016419767 - 20 -1257.550104148744 - 0 -LWPOLYLINE - 5 -648 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3301.774219281506 - 20 -1256.048735667427 - 10 -3300.774476750289 - 20 -1256.048921864945 - 0 -LWPOLYLINE - 5 -649 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3301.774219281506 - 20 -1256.048735667427 - 10 -3301.774219281506 - 20 -1256.048735667427 - 10 -3300.774476717226 - 20 -1256.048735667427 - 0 -LWPOLYLINE - 5 -64A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3301.824485587422 - 20 -1257.550104146532 - 10 -3301.824476721231 - 20 -1257.500104145787 - 0 -LWPOLYLINE - 5 -64B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3301.824334818404 - 20 -1256.700104148709 - 10 -3301.824210413499 - 20 -1255.998735667439 - 10 -3300.774476717226 - 20 -1255.998735667439 - 0 -LWPOLYLINE - 5 -64C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3300.774476717226 - 20 -1259.050104148744 - 10 -3300.774476717226 - 20 -1255.998735667439 - 10 -3300.624476717086 - 20 -1255.998735667439 - 0 -LINE - 5 -64D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3302.724219282391 - 20 -1255.998735667439 - 11 -3303.709826648236 - 21 -1255.998735667439 - 0 -LINE - 5 -64E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3302.724219282391 - 20 -1256.048735667427 - 11 -3303.709826648236 - 21 -1256.048735667427 - 0 -LINE - 5 -64F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3302.724476717179 - 20 -1257.550104148744 - 11 -3302.724476717179 - 21 -1257.500104148697 - 0 -LINE - 5 -650 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3301.824485586723 - 20 -1257.550104148744 - 11 -3302.724476717179 - 21 -1257.550104148744 - 0 -LINE - 5 -651 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3301.824219282251 - 20 -1256.048735667427 - 11 -3301.824219282251 - 21 -1255.998735667439 - 0 -LINE - 5 -652 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3302.724219282391 - 20 -1256.048735667427 - 11 -3302.724219282391 - 21 -1255.998735667439 - 0 -LINE - 5 -653 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3301.774219281506 - 20 -1256.048735667427 - 11 -3301.774196847809 - 21 -1256.048735667427 - 0 -LINE - 5 -654 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3301.774476716762 - 20 -1257.500104145787 - 11 -3301.824476721231 - 21 -1257.500104145787 - 0 -LINE - 5 -655 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3301.774476717226 - 20 -1256.700104148709 - 11 -3301.824476717972 - 21 -1256.700104148709 - 0 -LINE - 5 -656 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3301.774476717226 - 20 -1256.700104148709 - 11 -3301.774179179687 - 21 -1256.048735667427 - 0 -LINE - 5 -657 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3301.774476717226 - 20 -1256.700104148709 - 11 -3301.774476717226 - 21 -1257.500104148697 - 0 -LINE - 5 -658 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3302.774476717227 - 20 -1257.550104148744 - 11 -3302.774476717227 - 21 -1257.500104148697 - 0 -LINE - 5 -659 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3303.574476713782 - 20 -1257.550104146532 - 11 -3303.574476713782 - 21 -1257.500104145787 - 0 -LINE - 5 -65A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3303.574476717273 - 20 -1257.550104148744 - 11 -3302.774476717227 - 21 -1257.550104148744 - 0 -LWPOLYLINE - 5 -65B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3298.794476717245 - 20 -1256.050104161259 - 10 -3298.794476717245 - 20 -1259.280104148725 - 10 -3300.624476717086 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -65C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3298.844476717059 - 20 -1256.050104161259 - 10 -3298.844476717059 - 20 -1259.230104148737 - 10 -3300.624476717086 - 20 -1259.230104148737 - 0 -LWPOLYLINE - 5 -65D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3298.894476717105 - 20 -1256.050104161259 - 10 -3298.894476717105 - 20 -1259.180104148749 - 10 -3300.624476717086 - 20 -1259.180104148749 - 0 -LWPOLYLINE - 5 -65E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3299.024476717227 - 20 -1256.050104161259 - 10 -3299.024476717227 - 20 -1259.050104148744 - 10 -3300.624476717086 - 20 -1259.050104148744 - 0 -LINE - 5 -65F -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.502612257843 - 20 -1240.067414091609 - 11 -3299.502612257843 - 21 -1260.721494616649 - 0 -CIRCLE - 5 -660 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3299.502612257843 - 20 -1241.147899744741 - 40 -0.3105759447062155 - 0 -HATCH - 5 -661 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3299.813188202679 - 20 -1241.147899743053 - 11 -3299.502612257843 - 21 -1241.458475687716 - 72 - 1 - 10 -3299.502612257843 - 20 -1241.458475687716 - 11 -3299.502612257843 - 21 -1240.837323798332 - 72 - 1 - 10 -3299.502612257843 - 20 -1240.837323798332 - 11 -3299.813188202679 - 21 -1241.147899743053 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -662 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3299.502612257843 - 20 -1240.837323816202 - 10 -3299.813188193831 - 20 -1241.147899740957 - 10 -3299.502612257843 - 20 -1241.458475688181 - 10 -3299.502612257843 - 20 -1240.837323816202 - 0 -MTEXT - 5 -663 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3299.788579344517 - 20 -1241.193436495552 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -CIRCLE - 5 -664 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3299.502612257843 - 20 -1260.305064083717 - 40 -0.3105759447062155 - 0 -HATCH - 5 -665 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3299.813188202679 - 20 -1260.305064084648 - 11 -3299.502612257843 - 21 -1260.615640029369 - 72 - 1 - 10 -3299.502612257843 - 20 -1260.615640029369 - 11 -3299.502612257843 - 21 -1259.994488139928 - 72 - 1 - 10 -3299.502612257843 - 20 -1259.994488139928 - 11 -3299.813188202679 - 21 -1260.305064084648 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -666 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3299.502612257843 - 20 -1259.994488147728 - 10 -3299.813188197557 - 20 -1260.305064083717 - 10 -3299.502612257843 - 20 -1260.615640027157 - 10 -3299.502612257843 - 20 -1259.994488147728 - 0 -MTEXT - 5 -667 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3299.788579344517 - 20 -1260.350600837148 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -HATCH - 5 -668 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3305.53003487899 - 20 -1243.423737554054 - 11 -3305.53003487899 - 21 -1243.123737554066 - 72 - 1 - 10 -3305.53003487899 - 20 -1243.123737554066 - 11 -3305.830034879036 - 21 -1243.123737554066 - 72 - 1 - 10 -3305.830034879036 - 20 -1243.123737554066 - 11 -3305.53003487899 - 21 -1243.423737554054 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -669 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3305.53003487899 - 20 -1243.423737554054 - 11 -3305.230034878943 - 21 -1243.123737554066 - 72 - 1 - 10 -3305.230034878943 - 20 -1243.123737554066 - 11 -3305.53003487899 - 21 -1243.123737554066 - 72 - 1 - 10 -3305.53003487899 - 20 -1243.123737554066 - 11 -3305.53003487899 - 21 -1243.423737554054 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LINE - 5 -66A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3305.530034879688 - 20 -1243.423737553589 - 11 -3305.530034879688 - 21 -1241.299706538848 - 0 -LWPOLYLINE - 5 -66B -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3289.610538748326 - 20 -1243.823737554077 - 10 -3293.070538748289 - 20 -1243.823737554077 - 10 -3293.070538748289 - 20 -1245.952369962644 - 0 -DIMENSION - 5 -66C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D5 - 10 -3293.070538748289 - 20 -1261.079065790865 - 30 -0 - 11 -3287.221803563298 - 21 -1261.206589222733 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3281.373068378307 - 23 -1259.280104148725 - 33 -0 - 14 -3293.070538748289 - 24 -1259.280104148725 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -66D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D6 - 10 -3294.049122274159 - 20 -1245.952369962645 - 30 -0 - 11 -3293.921598842291 - 21 -1252.616237055684 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3293.070538748289 - 23 -1259.280104148725 - 33 -0 - 14 -3293.070538748289 - 24 -1245.952369962644 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -66E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D7 - 10 -3280.402680748146 - 20 -1259.280104148726 - 30 -0 - 11 -3280.275157316278 - 21 -1250.717369962687 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3281.373068378307 - 23 -1242.154635776649 - 33 -0 - 14 -3281.373068378307 - 24 -1259.280104148725 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -INSERT - 5 -66F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -tre - 10 -1789.751515634358 - 20 -1356.923699999461 - 30 -0 - 41 --0.0059048999998235 - 42 -0.0059048999997322 - 43 -0 - 50 -179.9911266057404 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -670 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -tre - 10 -1789.807194218505 - 20 -1358.730176527402 - 30 -0 - 41 --0.0059048999998235 - 42 -0.0059048999997322 - 43 -0 - 50 -179.9911266057404 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -LINE - 5 -671 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3300.774476717226 - 20 -1258.644932924595 - 11 -3301.208427953534 - 21 -1258.644932924595 - 0 -LINE - 5 -672 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3301.208427953534 - 20 -1258.644932924595 - 11 -3301.208427953534 - 21 -1258.684932924574 - 0 -LINE - 5 -673 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3301.208427953534 - 20 -1258.684932924574 - 11 -3300.774476717226 - 21 -1258.684932924574 - 0 -LINE - 5 -674 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3300.774476716761 - 20 -1258.018103768758 - 11 -3301.208427953068 - 21 -1258.018103768758 - 0 -LINE - 5 -675 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3301.208427953068 - 20 -1258.018103768758 - 11 -3301.208427953068 - 21 -1258.058103767864 - 0 -LINE - 5 -676 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3301.208427953068 - 20 -1258.058103767864 - 11 -3300.774476716761 - 21 -1258.058103767864 - 0 -INSERT - 5 -677 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbBlockReference - 2 -15 - 10 -4062.757693060674 - 20 -8221.425826757622 - 30 -0 - 41 -0.0094866649972689 - 42 -0.0094866649972689 - 43 -0 - 50 -89.99112660048513 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -MTEXT - 5 -678 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3301.78705061134 - 20 -1256.994305585045 - 30 -0 - 40 -0.22 - 41 -1.381111111111138 - 71 - 1 - 72 - 5 - 1 -\pt308;D2 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -INSERT - 5 -679 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -tre - 10 -3403.676925843814 - 20 -2770.100082705671 - 30 -0 - 41 --0.0059048999998235 - 42 -0.0059048999997322 - 43 -0 - 50 -89.9911266057404 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -67A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbBlockReference - 2 -15 - 10 --4434.939009629188 - 20 -412.0207373641314 - 30 -0 - 41 --0.0105407388858543 - 42 -0.0105407388858543 - 43 -0 - 50 -0.0088733995148438 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -MTEXT - 5 -67B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3303.006558738184 - 20 -1257.331142450508 - 30 -0 - 40 -0.22 - 41 -1.381111111111138 - 71 - 1 - 72 - 5 - 1 -\pt308;D2 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -67C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3302.180130573921 - 20 -1257.379249563906 - 30 -0 - 40 -0.22 - 41 -1.454444444444486 - 71 - 1 - 72 - 5 - 1 -\pt3.08;D3 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -INSERT - 5 -67D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbBlockReference - 2 -15 - 10 -11814.16996514331 - 20 -327.4700975784217 - 30 -0 - 41 -0.0115948127744398 - 42 -0.0115948127744398 - 43 -0 - 50 -359.9911266004852 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -LINE - 5 -67E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3302.774476717227 - 20 -1259.050104148744 - 11 -3302.774476717227 - 21 -1259.280104148725 - 0 -LINE - 5 -67F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3300.774476717226 - 20 -1259.050104148744 - 11 -3300.774476717226 - 21 -1259.280104148725 - 0 -LINE - 5 -680 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3301.974476717179 - 20 -1259.050104148744 - 11 -3301.974476717179 - 21 -1259.280104148725 - 0 -LINE - 5 -681 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3302.774476717227 - 20 -1259.280104148725 - 11 -3303.708122670651 - 21 -1259.280104148725 - 0 -LINE - 5 -682 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3302.774476717227 - 20 -1259.230104148737 - 11 -3303.708122670651 - 21 -1259.230104148737 - 0 -LINE - 5 -683 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3302.774476717227 - 20 -1259.180104148749 - 11 -3303.708122670651 - 21 -1259.180104148749 - 0 -LINE - 5 -684 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3302.774476717227 - 20 -1259.050104148744 - 11 -3303.708122670651 - 21 -1259.050104148744 - 0 -LINE - 5 -685 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3300.774476717226 - 20 -1259.280104148725 - 11 -3301.974476717179 - 21 -1259.280104148725 - 0 -LINE - 5 -686 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3300.774476717226 - 20 -1259.230104148737 - 11 -3301.974476717179 - 21 -1259.230104148737 - 0 -LINE - 5 -687 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3300.774476717226 - 20 -1259.180104148749 - 11 -3301.974476717179 - 21 -1259.180104148749 - 0 -LINE - 5 -688 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3300.774476717226 - 20 -1259.050104148744 - 11 -3301.974476717179 - 21 -1259.050104148744 - 0 -INSERT - 5 -689 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbBlockReference - 2 -15 - 10 -11040.33770562871 - 20 -410.5193688828149 - 30 -0 - 41 -0.0105407388858543 - 42 -0.0105407388858543 - 43 -0 - 50 -359.9911266004852 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -MTEXT - 5 -68A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3302.125557532999 - 20 -1256.012902952148 - 30 -0 - 40 -0.22 - 41 -1.33222222222225 - 71 - 1 - 72 - 5 - 1 -\pt308;D1 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -68B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3289.177517196164 - 20 -1240.247074862826 - 10 -3291.086696353044 - 20 -1240.67111403431 - 10 -3291.166303563863 - 20 -1241.271821681992 - 10 -3292.05901944451 - 20 -1240.043893054477 - 10 -3291.988317709649 - 20 -1240.83010695572 - 10 -3294.631075764543 - 20 -1241.395507029665 - 0 -LWPOLYLINE - 5 -68C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3305.830034879036 - 20 -1243.123737554066 - 10 -3305.230034878943 - 20 -1243.123737554066 - 10 -3305.53003487899 - 20 -1243.423737554054 - 10 -3305.830034879036 - 20 -1243.123737554066 - 0 -DIMENSION - 5 -68D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D8 - 10 -3300.22410247149 - 20 -1248.124625565833 - 30 -0 - 11 -3299.624289594358 - 21 -1248.2521489977 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3299.024476717227 - 23 -1247.752369962632 - 33 -0 - 14 -3300.22410247149 - 24 -1247.752369962632 - 34 -0 -100 -AcDbRotatedDimension - 0 -MTEXT - 5 -68E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3300.46796825272 - 20 -1243.638422377058 - 30 -0 - 40 -0.21 - 41 -1.18416666666668 - 71 - 1 - 72 - 5 - 1 -CUT OUT - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -LINE - 5 -68F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.624289596919 - 20 -1245.052369961224 - 11 -3299.624289596919 - 21 -1249.399006945721 - 0 -HATCH - 5 -690 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3299.624509939226 - 20 -1245.052369962679 - 11 -3299.624730284093 - 21 -1245.352369962667 - 72 - 1 - 10 -3299.624730284093 - 20 -1245.352369962667 - 11 -3299.928648714209 - 21 -1245.352369962667 - 72 - 1 - 10 -3299.928648714209 - 20 -1245.352369962667 - 11 -3299.624509939226 - 21 -1245.052369962679 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -691 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3299.624509939226 - 20 -1245.052369962679 - 11 -3299.339834515239 - 21 -1245.352369962667 - 72 - 1 - 10 -3299.339834515239 - 20 -1245.352369962667 - 11 -3299.624730284093 - 21 -1245.352369962667 - 72 - 1 - 10 -3299.624730284093 - 20 -1245.352369962667 - 11 -3299.624509939226 - 21 -1245.052369962679 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -692 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3299.928648714209 - 20 -1245.352369962667 - 10 -3299.624509939226 - 20 -1245.052369962679 - 10 -3299.339834515239 - 20 -1245.352369962667 - 10 -3299.928648714209 - 20 -1245.352369962667 - 0 -MTEXT - 5 -693 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3299.299492937281 - 20 -1249.322837113054 - 30 -0 - 40 -0.21 - 41 -0.3033333333333333 - 71 - 1 - 72 - 5 - 1 -UP - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -694 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3301.413372402545 - 20 -1246.491755528434 - 30 -0 - 40 -0.21 - 41 -0.3033333333333463 - 71 - 1 - 72 - 5 - 1 -DN - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -695 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3327.345456386451 - 20 -1259.280104146979 - 10 -3327.345456386451 - 20 -1259.280104146979 - 10 -3327.345456386451 - 20 -1245.952385825745 - 0 -LINE - 5 -696 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3315.647986019496 - 20 -1243.321229865483 - 11 -3315.647986019496 - 21 -1256.050104161433 - 0 -LINE - 5 -697 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1243.321229862398 - 11 -3315.877986022039 - 21 -1256.050104161259 - 0 -LINE - 5 -698 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3327.11545639229 - 20 -1259.050104148744 - 11 -3327.11545639229 - 21 -1245.952385825629 - 0 -LINE - 5 -699 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1242.252369962632 - 11 -3319.157986022066 - 21 -1242.252369962632 - 0 -LINE - 5 -69A -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3323.885456392076 - 20 -1243.423737554054 - 11 -3323.885456392076 - 21 -1242.823737554077 - 0 -LWPOLYLINE - 5 -69B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3315.647986022057 - 20 -1243.321229862398 - 10 -3315.647986022057 - 20 -1241.721707735967 - 10 -3315.647986022057 - 20 -1241.721707735967 - 10 -3315.877986022039 - 20 -1241.721707735967 - 10 -3315.877986022039 - 20 -1243.321229862398 - 0 -LWPOLYLINE - 5 -69C -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3324.115456392291 - 20 -1243.923737554054 - 10 -3324.115456392291 - 20 -1242.900966822169 - 10 -3321.032986022066 - 20 -1241.721707735967 - 10 -3315.877986022039 - 20 -1241.721707735967 - 0 -LINE - 5 -69D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077986021992 - 20 -1243.552369962679 - 11 -3317.077986021992 - 21 -1242.352369962667 - 0 -LINE - 5 -69E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1243.852369962668 - 11 -3319.177986022085 - 21 -1243.852369962668 - 0 -LINE - 5 -69F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1244.152369962656 - 11 -3319.177986022085 - 21 -1244.152369962656 - 0 -LINE - 5 -6A0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1244.452369962644 - 11 -3319.177986022085 - 21 -1244.452369962644 - 0 -LINE - 5 -6A1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1244.752369962633 - 11 -3319.177986022085 - 21 -1244.752369962633 - 0 -LINE - 5 -6A2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.127986022038 - 20 -1243.552369962679 - 11 -3319.177986022085 - 21 -1243.552369962679 - 0 -LWPOLYLINE - 5 -6A3 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.077611776302 - 20 -1246.852369962667 - 10 -3317.077611776302 - 20 -1244.152369962656 - 0 -LWPOLYLINE - 5 -6A4 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3317.077611776302 - 20 -1243.852369962668 - 10 -3317.077611776302 - 20 -1243.552369962679 - 10 -3317.977986022132 - 20 -1243.552369962679 - 10 -3317.977986022132 - 20 -1245.052369962679 - 0 -LWPOLYLINE - 5 -6A5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.977986022132 - 20 -1245.152369962656 - 10 -3317.977986022132 - 20 -1245.652369962656 - 0 -LINE - 5 -6A6 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3317.047611776274 - 20 -1246.852369962667 - 11 -3317.047611776274 - 21 -1244.152369962656 - 0 -LINE - 5 -6A7 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3317.047611776274 - 20 -1243.852369962668 - 11 -3317.047611776274 - 21 -1243.522369962651 - 0 -LINE - 5 -6A8 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3317.047611776274 - 20 -1243.522369962651 - 11 -3318.00798602216 - 21 -1243.522369962651 - 0 -LINE - 5 -6A9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3318.00798602216 - 20 -1245.052369962679 - 11 -3318.00798602216 - 21 -1245.652369962656 - 0 -LINE - 5 -6AA -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3317.017611776479 - 20 -1246.852369962667 - 11 -3317.017611776479 - 21 -1244.152369962656 - 0 -LINE - 5 -6AB -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3317.017611776479 - 20 -1243.852369962668 - 11 -3317.017611776479 - 21 -1243.492369962681 - 0 -LINE - 5 -6AC -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3317.017611776479 - 20 -1243.492369962681 - 11 -3318.037986022189 - 21 -1243.492369962681 - 0 -LINE - 5 -6AD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3318.037986022189 - 20 -1245.052369962679 - 11 -3318.037986022189 - 21 -1245.652369962656 - 0 -LINE - 5 -6AE -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1246.852369962667 - 11 -3317.077611776302 - 21 -1244.752369962633 - 0 -LINE - 5 -6AF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3319.177986022085 - 20 -1244.752369962633 - 11 -3319.177986022085 - 21 -1245.052369962679 - 0 -LINE - 5 -6B0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1243.852369962668 - 11 -3315.877986022039 - 21 -1243.852369962668 - 0 -LINE - 5 -6B1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1243.552369962679 - 11 -3315.877986022039 - 21 -1243.552369962679 - 0 -LINE - 5 -6B2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1244.152369962656 - 11 -3315.877986022039 - 21 -1244.152369962656 - 0 -LINE - 5 -6B3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1244.452369962644 - 11 -3315.877986022039 - 21 -1244.452369962644 - 0 -LINE - 5 -6B4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1244.752369962633 - 11 -3315.877986022039 - 21 -1244.752369962633 - 0 -LINE - 5 -6B5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1245.052369962679 - 11 -3315.877986022039 - 21 -1245.052369962679 - 0 -LINE - 5 -6B6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1245.352369962667 - 11 -3315.877986022039 - 21 -1245.352369962667 - 0 -LINE - 5 -6B7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1245.652369962656 - 11 -3315.877986022039 - 21 -1245.652369962656 - 0 -LINE - 5 -6B8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1245.952369962644 - 11 -3315.877986022039 - 21 -1245.952369962644 - 0 -LINE - 5 -6B9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1246.252369962633 - 11 -3315.877986022039 - 21 -1246.252369962633 - 0 -LINE - 5 -6BA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1246.552369962679 - 11 -3315.877986022039 - 21 -1246.552369962679 - 0 -LINE - 5 -6BB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1246.852369962667 - 11 -3315.877986022039 - 21 -1246.852369962667 - 0 -LINE - 5 -6BC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1243.602689753345 - 11 -3317.977986022132 - 21 -1242.352369962667 - 0 -LINE - 5 -6BD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.677986022085 - 20 -1243.552369962679 - 11 -3317.677986022085 - 21 -1242.352369962667 - 0 -LINE - 5 -6BE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.37798602204 - 20 -1243.552369962679 - 11 -3317.37798602204 - 21 -1242.352369962667 - 0 -LINE - 5 -6BF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3327.11545639229 - 20 -1245.952385825629 - 11 -3327.34696792718 - 21 -1245.952369962644 - 0 -LWPOLYLINE - 5 -6C0 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3315.877986022039 - 20 -1242.352369962726 - 10 -3319.207986022113 - 20 -1242.352369962726 - 10 -3319.207986022113 - 20 -1242.722369962663 - 0 -LWPOLYLINE - 5 -6C1 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3315.877986022039 - 20 -1242.302369962737 - 10 -3319.257986022159 - 20 -1242.302369962737 - 10 -3319.257986022159 - 20 -1242.722369962663 - 0 -LWPOLYLINE - 5 -6C2 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3315.877986022039 - 20 -1242.252369962749 - 10 -3319.307986021974 - 20 -1242.252369962749 - 10 -3319.307986021974 - 20 -1242.722369962663 - 0 -LINE - 5 -6C3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.977986022112 - 20 -1245.652369964402 - 11 -3319.177986022065 - 21 -1245.652369964402 - 0 -LINE - 5 -6C4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1245.352369962667 - 11 -3319.177986022085 - 21 -1245.352369962667 - 0 -LINE - 5 -6C5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1245.652369962656 - 11 -3319.177986022085 - 21 -1245.652369962656 - 0 -LWPOLYLINE - 5 -6C6 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3323.885456392076 - 20 -1243.823737554077 - 10 -3327.345456392271 - 20 -1243.823737554077 - 10 -3327.345456392271 - 20 -1245.238323131343 - 0 -LWPOLYLINE - 5 -6C7 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3323.885456392076 - 20 -1243.873737554066 - 10 -3327.295456392225 - 20 -1243.873737554066 - 10 -3327.295456392225 - 20 -1245.238323131343 - 0 -LWPOLYLINE - 5 -6C8 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3323.885456392076 - 20 -1243.923737554054 - 10 -3327.245456392179 - 20 -1243.923737554054 - 10 -3327.245456392179 - 20 -1245.238323131343 - 0 -LWPOLYLINE - 5 -6C9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3327.34696792718 - 20 -1245.952369962644 - 10 -3327.345456392271 - 20 -1245.238323131343 - 10 -3327.11545639229 - 20 -1245.238323131343 - 10 -3327.11545639229 - 20 -1245.952385825629 - 0 -LINE - 5 -6CA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3319.406631975668 - 20 -1244.402369962656 - 11 -3319.406631975668 - 21 -1244.445176272304 - 0 -LINE - 5 -6CB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3319.406631975668 - 20 -1244.48176036129 - 11 -3319.406631975668 - 21 -1244.52456667088 - 0 -LINE - 5 -6CC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 52 -370 - 0 -100 -AcDbLine - 10 -3320.681631975574 - 20 -1244.402369962656 - 11 -3320.681631975574 - 21 -1243.472369962663 - 0 -LINE - 5 -6CD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3320.681631975574 - 20 -1244.552369962621 - 11 -3320.529808998806 - 21 -1244.552369962621 - 0 -LINE - 5 -6CE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3319.529808998807 - 20 -1244.552369962679 - 11 -3319.406631975668 - 21 -1244.552369962679 - 0 -LINE - 5 -6CF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3320.681631975574 - 20 -1244.752369962633 - 11 -3320.529808998806 - 21 -1244.752369962633 - 0 -LINE - 5 -6D0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3319.529808998807 - 20 -1244.752369962633 - 11 -3319.177986022085 - 21 -1244.752369962633 - 0 -LINE - 5 -6D1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3319.406631975668 - 20 -1244.402369962656 - 11 -3319.406631975668 - 21 -1244.445176272304 - 0 -LINE - 5 -6D2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3319.406631975668 - 20 -1244.48176036129 - 11 -3319.406631975668 - 21 -1244.52456667088 - 0 -LWPOLYLINE - 5 -6D3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 0 - 43 -0 - 10 -3320.681631975574 - 20 -1243.472369962663 - 10 -3320.681631975574 - 20 -1244.752369962633 - 10 -3320.881631975528 - 20 -1244.752369962633 - 10 -3321.031631975668 - 20 -1244.752369962633 - 10 -3321.031631975668 - 20 -1244.522369962651 - 10 -3320.881631975528 - 20 -1244.522369962651 - 10 -3320.881631975528 - 20 -1243.472369962663 - 10 -3320.681631975574 - 20 -1243.472369962663 - 0 -LINE - 5 -6D4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3319.177986022085 - 20 -1243.472369962663 - 11 -3319.177986022085 - 21 -1244.752369962633 - 0 -LINE - 5 -6D5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3319.377986022038 - 20 -1243.672369962675 - 11 -3319.377986022038 - 21 -1244.252369962632 - 0 -LWPOLYLINE - 5 -6D6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3319.37663197564 - 20 -1243.472369962663 - 10 -3319.177986022085 - 20 -1243.472369962663 - 10 -3319.177986022085 - 20 -1242.722369962663 - 10 -3319.177986022085 - 20 -1242.722369962663 - 0 -LINE - 5 -6D7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3319.529808998807 - 20 -1244.552369962679 - 11 -3319.529808998807 - 21 -1244.752369962633 - 0 -LINE - 5 -6D8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3320.529808998806 - 20 -1244.552369962621 - 11 -3320.529808998806 - 21 -1244.752369962633 - 0 -LWPOLYLINE - 5 -6D9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 1 - 43 -0 - 10 -3319.456631975481 - 20 -1244.502369962632 - 10 -3320.631631975528 - 20 -1244.502369962632 - 10 -3320.631631975528 - 20 -1242.972369962663 - 10 -3319.426631975686 - 20 -1242.972369962663 - 10 -3319.426631975686 - 20 -1244.202369962644 - 10 -3319.456631975481 - 20 -1244.202369962644 - 0 -LWPOLYLINE - 5 -6DA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 1 - 43 -0 - 10 -3319.506631975528 - 20 -1244.452369962644 - 10 -3320.581631975482 - 20 -1244.452369962644 - 10 -3320.581631975482 - 20 -1243.022369962651 - 10 -3319.4766319755 - 20 -1243.022369962651 - 10 -3319.4766319755 - 20 -1244.152369962656 - 10 -3319.506631975528 - 20 -1244.152369962656 - 0 -LINE - 5 -6DB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3319.406631975668 - 20 -1244.552369962679 - 11 -3320.581631975482 - 21 -1243.022369962651 - 0 -LINE - 5 -6DC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3320.681631975574 - 20 -1244.552369962679 - 11 -3319.37663197564 - 21 -1242.922369962616 - 0 -MTEXT - 5 -6DD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3319.684990863782 - 20 -1243.275681681291 - 30 -0 - 40 -0.21 - 41 -0.5133333333333333 - 71 - 1 - 72 - 5 - 1 -LIFT - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -6DE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3320.054133306723 - 20 -1243.303355389158 - 30 -0 - 40 -0.21 - 41 -1.026666666666706 - 71 - 1 - 72 - 5 - 1 -163X130 - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -LINE - 5 -6DF -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3319.176631975687 - 20 -1244.752369962633 - 11 -3319.177986022085 - 21 -1245.052369962679 - 0 -LWPOLYLINE - 5 -6E0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3319.37663197564 - 20 -1243.423737554054 - 10 -3319.37663197564 - 20 -1242.722369962663 - 10 -3319.177986022085 - 20 -1242.722369962663 - 10 -3319.177986022085 - 20 -1243.423737554054 - 0 -HATCH - 5 -6E1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3316.478019244037 - 20 -1243.852369962668 - 11 -3316.478239589138 - 21 -1243.552369962679 - 72 - 1 - 10 -3316.478239589138 - 20 -1243.552369962679 - 11 -3316.782158019022 - 21 -1243.552369962679 - 72 - 1 - 10 -3316.782158019022 - 20 -1243.552369962679 - 11 -3316.478019244037 - 21 -1243.852369962668 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -6E2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3316.478019244037 - 20 -1243.852369962668 - 11 -3316.193343820052 - 21 -1243.552369962679 - 72 - 1 - 10 -3316.193343820052 - 20 -1243.552369962679 - 11 -3316.478239589138 - 21 -1243.552369962679 - 72 - 1 - 10 -3316.478239589138 - 20 -1243.552369962679 - 11 -3316.478019244037 - 21 -1243.852369962668 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -6E3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3318.591678364434 - 20 -1246.567925359879 - 10 -3318.591678364434 - 20 -1243.552369962679 - 10 -3318.591678364434 - 20 -1242.922737527056 - 10 -3316.478702043416 - 20 -1242.922737527056 - 10 -3316.47779889917 - 20 -1244.152369962656 - 0 -LWPOLYLINE - 5 -6E4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3316.782158019022 - 20 -1243.552369962679 - 10 -3316.478019244037 - 20 -1243.852369962668 - 10 -3316.193343820052 - 20 -1243.552369962679 - 10 -3316.782158019022 - 20 -1243.552369962679 - 0 -LWPOLYLINE - 5 -6E5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3318.00798602216 - 20 -1243.522369962651 - 10 -3318.00798602216 - 20 -1245.402369962702 - 10 -3317.047611776274 - 20 -1245.402369962702 - 0 -LWPOLYLINE - 5 -6E6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3318.037986022189 - 20 -1243.492369962681 - 10 -3318.037986022189 - 20 -1245.452369962691 - 10 -3317.047611776274 - 20 -1245.452369962691 - 0 -LINE - 5 -6E7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3319.177986022085 - 20 -1245.052369962679 - 11 -3319.177986022085 - 21 -1245.652369962656 - 0 -LWPOLYLINE - 5 -6E8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3319.176631975687 - 20 -1244.752369962633 - 10 -3319.177986022085 - 20 -1245.052369962679 - 0 -LWPOLYLINE - 5 -6E9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3319.2266314663 - 20 -1244.752144290542 - 10 -3319.227985512699 - 20 -1245.05214429053 - 0 -LWPOLYLINE - 5 -6EA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3319.276630956912 - 20 -1244.751918618393 - 10 -3319.277985003544 - 20 -1245.051918618439 - 0 -LWPOLYLINE - 5 -6EB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3319.177986022085 - 20 -1245.052369962679 - 10 -3319.277985003544 - 20 -1245.051918618439 - 0 -LINE - 5 -6EC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1256.300104148744 - 11 -3316.62798602204 - 21 -1256.300104148744 - 0 -LINE - 5 -6ED -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1256.500104148697 - 11 -3316.62798602204 - 21 -1256.500104148697 - 0 -LINE - 5 -6EE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1256.700104148709 - 11 -3316.62798602204 - 21 -1256.700104148709 - 0 -LINE - 5 -6EF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1256.900104148721 - 11 -3316.62798602204 - 21 -1256.900104148721 - 0 -LINE - 5 -6F0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1257.100104148732 - 11 -3316.62798602204 - 21 -1257.100104148732 - 0 -LINE - 5 -6F1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1257.300104148744 - 11 -3316.62798602204 - 21 -1257.300104148744 - 0 -LINE - 5 -6F2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1257.500104148697 - 11 -3316.62798602204 - 21 -1257.500104148697 - 0 -LINE - 5 -6F3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1257.700104148709 - 11 -3316.62798602204 - 21 -1257.700104148709 - 0 -LINE - 5 -6F4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1257.900104148721 - 11 -3316.62798602204 - 21 -1257.900104148721 - 0 -LINE - 5 -6F5 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1258.100104148732 - 11 -3316.62798602204 - 21 -1258.100104148732 - 0 -LINE - 5 -6F6 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1258.300104148744 - 11 -3316.62798602204 - 21 -1258.300104148744 - 0 -LWPOLYLINE - 5 -6F7 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3316.62798602204 - 20 -1258.300104148744 - 10 -3316.62798602204 - 20 -1258.100104148732 - 0 -LWPOLYLINE - 5 -6F8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3316.62798602204 - 20 -1257.900104148721 - 10 -3316.62798602204 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -6F9 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3316.727986022132 - 20 -1258.300104148744 - 10 -3316.727986022132 - 20 -1256.300104148744 - 0 -LINE - 5 -6FA -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1256.300104148744 - 11 -3317.477986022132 - 21 -1256.300104148744 - 0 -LINE - 5 -6FB -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1256.500104148697 - 11 -3317.477986022132 - 21 -1256.500104148697 - 0 -LINE - 5 -6FC -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1256.700104148709 - 11 -3317.477986022132 - 21 -1256.700104148709 - 0 -LINE - 5 -6FD -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1256.900104148721 - 11 -3317.477986022132 - 21 -1256.900104148721 - 0 -LINE - 5 -6FE -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1257.100104148732 - 11 -3317.477986022132 - 21 -1257.100104148732 - 0 -LINE - 5 -6FF -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1257.300104148744 - 11 -3317.477986022132 - 21 -1257.300104148744 - 0 -LINE - 5 -700 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1257.500104148697 - 11 -3317.477986022132 - 21 -1257.500104148697 - 0 -LINE - 5 -701 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1257.700104148709 - 11 -3317.477986022132 - 21 -1257.700104148709 - 0 -LINE - 5 -702 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1257.900104148721 - 11 -3317.477986022132 - 21 -1257.900104148721 - 0 -LINE - 5 -703 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1258.100104148732 - 11 -3317.477986022132 - 21 -1258.100104148732 - 0 -LINE - 5 -704 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1258.300104148744 - 11 -3317.477986022132 - 21 -1258.300104148744 - 0 -LWPOLYLINE - 5 -705 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3316.62798602204 - 20 -1256.300104148744 - 10 -3316.62798602204 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -706 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3316.62798602204 - 20 -1258.100104148732 - 10 -3316.62798602204 - 20 -1258.300104148744 - 10 -3316.727986022132 - 20 -1258.300104148744 - 10 -3316.727986022132 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -707 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3316.59798602201 - 20 -1256.300104148744 - 10 -3316.59798602201 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -708 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3316.59798602201 - 20 -1258.100104148732 - 10 -3316.59798602201 - 20 -1258.330104148714 - 10 -3316.757986022159 - 20 -1258.330104148714 - 10 -3316.757986022159 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -709 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3316.567986021983 - 20 -1256.300104148744 - 10 -3316.567986021983 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -70A -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3316.567986021983 - 20 -1258.100104148732 - 10 -3316.567986021983 - 20 -1258.360104148741 - 10 -3316.787986022188 - 20 -1258.360104148741 - 10 -3316.787986022188 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -70B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3315.647986022057 - 20 -1256.050104161259 - 10 -3315.647986019496 - 20 -1259.280104146979 - 10 -3317.477986017709 - 20 -1259.280104146979 - 0 -LWPOLYLINE - 5 -70C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3315.697986022104 - 20 -1256.050104161259 - 10 -3315.697986022104 - 20 -1259.230104148737 - 10 -3317.477986022132 - 20 -1259.230104148737 - 0 -LWPOLYLINE - 5 -70D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3315.74798602215 - 20 -1256.050104161259 - 10 -3315.74798602215 - 20 -1259.180104148749 - 10 -3317.477986022132 - 20 -1259.180104148749 - 0 -LWPOLYLINE - 5 -70E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3315.877986022039 - 20 -1256.050104161259 - 10 -3315.877986022039 - 20 -1259.050104148744 - 10 -3317.477986022132 - 20 -1259.050104148744 - 0 -LINE - 5 -70F -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3324.115456392291 - 20 -1243.423737554054 - 11 -3319.37663197564 - 21 -1242.722369962663 - 0 -LINE - 5 -710 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3324.108135909075 - 20 -1243.473198756284 - 11 -3319.369311492425 - 21 -1242.771831164893 - 0 -LINE - 5 -711 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3324.10081542586 - 20 -1243.522659958515 - 11 -3319.36199100921 - 21 -1242.821292367123 - 0 -LINE - 5 -712 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3320.881631975528 - 20 -1243.423737554054 - 11 -3320.881631975528 - 21 -1243.04620614968 - 0 -LINE - 5 -713 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3320.831631975482 - 20 -1243.423737554054 - 11 -3320.831631975482 - 21 -1243.04620614968 - 0 -LINE - 5 -714 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3320.781631975668 - 20 -1243.423737554054 - 11 -3320.781631975668 - 21 -1243.04620614968 - 0 -LINE - 5 -715 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3320.681631975574 - 20 -1243.423737554054 - 11 -3320.681631975574 - 21 -1243.016605238954 - 0 -LINE - 5 -716 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.35612156475 - 20 -1240.067414091609 - 11 -3316.35612156475 - 21 -1260.721494616649 - 0 -CIRCLE - 5 -717 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3316.35612156475 - 20 -1241.147899744741 - 40 -0.3105759447062155 - 0 -HATCH - 5 -718 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3316.666697507491 - 20 -1241.147899743053 - 11 -3316.356121562887 - 21 -1241.458475687716 - 72 - 1 - 10 -3316.356121562887 - 20 -1241.458475687716 - 11 -3316.356121562887 - 21 -1240.837323798332 - 72 - 1 - 10 -3316.356121562887 - 20 -1240.837323798332 - 11 -3316.666697507491 - 21 -1241.147899743053 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -719 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3316.35612156475 - 20 -1240.837323808751 - 10 -3316.666697504465 - 20 -1241.147899744741 - 10 -3316.35612156475 - 20 -1241.458475688181 - 10 -3316.35612156475 - 20 -1240.837323808751 - 0 -MTEXT - 5 -71A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3316.642088649562 - 20 -1241.193436495552 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -CIRCLE - 5 -71B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3316.35612156475 - 20 -1260.305064083717 - 40 -0.3105759447062155 - 0 -HATCH - 5 -71C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3316.666697507491 - 20 -1260.305064084648 - 11 -3316.356121562887 - 21 -1260.615640029369 - 72 - 1 - 10 -3316.356121562887 - 20 -1260.615640029369 - 11 -3316.356121562887 - 21 -1259.994488139928 - 72 - 1 - 10 -3316.356121562887 - 20 -1259.994488139928 - 11 -3316.666697507491 - 21 -1260.305064084648 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -71D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3316.35612156475 - 20 -1259.994488155178 - 10 -3316.666697500739 - 20 -1260.305064079934 - 10 -3316.35612156475 - 20 -1260.615640027157 - 10 -3316.35612156475 - 20 -1259.994488155178 - 0 -MTEXT - 5 -71E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3316.642088649562 - 20 -1260.350600837148 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -71F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.477986022132 - 20 -1259.280104148725 - 10 -3317.627986022039 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -720 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3318.827986021992 - 20 -1259.280104148725 - 10 -3319.62798602204 - 20 -1259.280104148725 - 0 -LINE - 5 -721 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3318.827986021992 - 20 -1259.050104148744 - 11 -3319.62798602204 - 21 -1259.050104148744 - 0 -LWPOLYLINE - 5 -722 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.477986022132 - 20 -1259.280104148725 - 10 -3317.627986022039 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -723 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.477986022132 - 20 -1259.050104148744 - 10 -3317.477986022132 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -724 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.477986022132 - 20 -1255.998735667439 - 10 -3317.477986022132 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -725 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.627986022039 - 20 -1256.048921864945 - 10 -3317.627986022039 - 20 -1259.050104148744 - 0 -LWPOLYLINE - 5 -726 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.627986022039 - 20 -1257.550104148744 - 10 -3317.928084941348 - 20 -1257.550104148744 - 0 -LWPOLYLINE - 5 -727 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.627986022039 - 20 -1257.550104148744 - 10 -3318.677994891537 - 20 -1257.550104148744 - 0 -LWPOLYLINE - 5 -728 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3319.577986021992 - 20 -1257.550104148744 - 10 -3319.577986021992 - 20 -1259.050104148744 - 0 -LWPOLYLINE - 5 -729 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.627986022039 - 20 -1257.500104148697 - 10 -3318.677986022784 - 20 -1257.500104148697 - 0 -LWPOLYLINE - 5 -72A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3319.577986021992 - 20 -1257.500104148697 - 10 -3319.62798602204 - 20 -1257.500104148697 - 10 -3319.62798602204 - 20 -1259.050104148744 - 0 -LINE - 5 -72B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3320.793525724673 - 20 -1256.048360379122 - 11 -3320.793525724673 - 21 -1259.050104148744 - 0 -LINE - 5 -72C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3320.693525724812 - 20 -1256.048360379122 - 11 -3320.693525724812 - 21 -1259.050104148744 - 0 -LWPOLYLINE - 5 -72D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3320.427986020688 - 20 -1257.500104145787 - 10 -3320.693525726441 - 20 -1257.500104145787 - 0 -LWPOLYLINE - 5 -72E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3320.427986022085 - 20 -1257.550104148744 - 10 -3320.693525724812 - 20 -1257.550104148744 - 0 -LWPOLYLINE - 5 -72F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3318.627728586318 - 20 -1256.048735667427 - 10 -3317.627986055101 - 20 -1256.048921864945 - 0 -LWPOLYLINE - 5 -730 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3318.627728586318 - 20 -1256.048735667427 - 10 -3318.627728586318 - 20 -1256.048735667427 - 10 -3317.627986022039 - 20 -1256.048735667427 - 0 -LWPOLYLINE - 5 -731 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3318.677994891537 - 20 -1257.550104148744 - 10 -3318.677986022784 - 20 -1257.500104148697 - 0 -LWPOLYLINE - 5 -732 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3318.677844123217 - 20 -1256.700104148709 - 10 -3318.677719718543 - 20 -1255.998735667439 - 10 -3317.627986022039 - 20 -1255.998735667439 - 0 -LWPOLYLINE - 5 -733 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3317.627986022039 - 20 -1259.050104148744 - 10 -3317.627986022039 - 20 -1255.998735667439 - 10 -3317.477986022132 - 20 -1255.998735667439 - 0 -LINE - 5 -734 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3319.577728587203 - 20 -1255.998735667439 - 11 -3320.563335953281 - 21 -1255.998735667439 - 0 -LINE - 5 -735 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3319.577728587203 - 20 -1256.048735667427 - 11 -3320.563335953281 - 21 -1256.048735667427 - 0 -LINE - 5 -736 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3319.577986021992 - 20 -1257.550104148744 - 11 -3319.577986021992 - 21 -1257.500104148697 - 0 -LINE - 5 -737 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3318.677994891537 - 20 -1257.550104148744 - 11 -3319.577986021992 - 21 -1257.550104148744 - 0 -LINE - 5 -738 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3318.677728587296 - 20 -1256.048735667427 - 11 -3318.677728587296 - 21 -1255.998735667439 - 0 -LINE - 5 -739 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3319.577728587203 - 20 -1256.048735667427 - 11 -3319.577728587203 - 21 -1255.998735667439 - 0 -LINE - 5 -73A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3318.627728586318 - 20 -1256.048735667427 - 11 -3318.62770615262 - 21 -1256.048735667427 - 0 -LINE - 5 -73B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3318.627986022038 - 20 -1257.500104148697 - 11 -3318.677986022784 - 21 -1257.500104148697 - 0 -LINE - 5 -73C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3318.627986022038 - 20 -1256.700104148709 - 11 -3318.677986022784 - 21 -1256.700104148709 - 0 -LINE - 5 -73D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3318.627986022038 - 20 -1256.700104148709 - 11 -3318.627688484499 - 21 -1256.048735667427 - 0 -LINE - 5 -73E -100 -AcDbEntity - 8 -BLK_1_FLR_1_WATER_CLOSET - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbLine - 10 -3318.627986022038 - 20 -1256.700104148709 - 11 -3318.627986022038 - 21 -1257.500104148697 - 0 -LINE - 5 -73F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3319.62798602204 - 20 -1257.550104148744 - 11 -3319.62798602204 - 21 -1257.500104148697 - 0 -LINE - 5 -740 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3320.427986020688 - 20 -1257.550104146532 - 11 -3320.427986020688 - 21 -1257.500104145787 - 0 -LINE - 5 -741 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3320.427986022085 - 20 -1257.550104148744 - 11 -3319.62798602204 - 21 -1257.550104148744 - 0 -INSERT - 5 -742 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -tre - 10 -1806.60502493917 - 20 -1356.923699999461 - 30 -0 - 41 --0.0059048999998235 - 42 -0.0059048999997322 - 43 -0 - 50 -179.9911266057404 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -743 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbBlockReference - 2 -15 - 10 -4079.611202365717 - 20 -8221.425826757622 - 30 -0 - 41 -0.0094866649972689 - 42 -0.0094866649972689 - 43 -0 - 50 -89.99112660048513 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -MTEXT - 5 -744 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3318.640559916152 - 20 -1256.994305585045 - 30 -0 - 40 -0.22 - 41 -1.381111111111138 - 71 - 1 - 72 - 5 - 1 -\pt308;D2 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -745 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3317.903847595444 - 20 -1256.633173740993 - 30 -0 - 40 -0.18 - 41 -1.250000000000011 - 71 - 1 - 72 - 5 - 1 -\pt2.52;WC\P1.45X1.00 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -INSERT - 5 -746 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -tre - 10 -3420.530435148859 - 20 -2770.100082705671 - 30 -0 - 41 --0.0059048999998235 - 42 -0.0059048999997322 - 43 -0 - 50 -89.9911266057404 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -747 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbBlockReference - 2 -15 - 10 --4418.085500324377 - 20 -412.0207373641314 - 30 -0 - 41 --0.0105407388858543 - 42 -0.0105407388858543 - 43 -0 - 50 -0.0088733995148438 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -MTEXT - 5 -748 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3319.860068043229 - 20 -1257.331142450508 - 30 -0 - 40 -0.22 - 41 -1.381111111111138 - 71 - 1 - 72 - 5 - 1 -\pt308;D2 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -749 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3319.033639878966 - 20 -1257.379249563906 - 30 -0 - 40 -0.22 - 41 -1.454444444444486 - 71 - 1 - 72 - 5 - 1 -\pt3.08;D3 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -LINE - 5 -74A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3319.62798602204 - 20 -1259.050104148744 - 11 -3319.62798602204 - 21 -1259.280104148725 - 0 -LINE - 5 -74B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3317.627986022039 - 20 -1259.050104148744 - 11 -3317.627986022039 - 21 -1259.280104148725 - 0 -LINE - 5 -74C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3318.827986021992 - 20 -1259.050104148744 - 11 -3318.827986021992 - 21 -1259.280104148725 - 0 -LINE - 5 -74D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3319.62798602204 - 20 -1259.280104148725 - 11 -3320.561631975464 - 21 -1259.280104148725 - 0 -LINE - 5 -74E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3319.62798602204 - 20 -1259.230104148737 - 11 -3320.561631975464 - 21 -1259.230104148737 - 0 -LINE - 5 -74F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3319.62798602204 - 20 -1259.180104148749 - 11 -3320.561631975464 - 21 -1259.180104148749 - 0 -LINE - 5 -750 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3319.62798602204 - 20 -1259.050104148744 - 11 -3320.561631975464 - 21 -1259.050104148744 - 0 -LINE - 5 -751 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3317.627986022039 - 20 -1259.280104148725 - 11 -3318.827986021992 - 21 -1259.280104148725 - 0 -LINE - 5 -752 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3317.627986022039 - 20 -1259.230104148737 - 11 -3318.827986021992 - 21 -1259.230104148737 - 0 -LINE - 5 -753 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3317.627986022039 - 20 -1259.180104148749 - 11 -3318.827986021992 - 21 -1259.180104148749 - 0 -LINE - 5 -754 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3317.627986022039 - 20 -1259.050104148744 - 11 -3318.827986021992 - 21 -1259.050104148744 - 0 -MTEXT - 5 -755 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3319.722613572841 - 20 -1258.560485614987 - 30 -0 - 40 -0.18 - 41 -1.190000000000011 - 71 - 1 - 72 - 5 - 1 -\pt252;WC\P1.06X1.50 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 --0.008873397653922366 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -756 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3318.979066837812 - 20 -1256.012902952148 - 30 -0 - 40 -0.22 - 41 -1.33222222222225 - 71 - 1 - 72 - 5 - 1 -\pt308;D1 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -757 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3321.061631975464 - 20 -1259.280104148725 - 10 -3327.345456392271 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -758 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3321.061631975464 - 20 -1259.050104148744 - 10 -3327.345456392271 - 20 -1259.050104148744 - 0 -LWPOLYLINE - 5 -759 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3300.249476718251 - 20 -1257.700104148767 - 10 -3300.249476718251 - 20 -1258.743019191257 - 10 -3299.417575473432 - 20 -1258.743019191257 - 10 -3299.417575473432 - 20 -1255.706959677569 - 0 -MTEXT - 5 -75A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3299.317210980691 - 20 -1255.661184545897 - 30 -0 - 40 -0.21 - 41 -0.3033333333333333 - 71 - 1 - 72 - 5 - 1 -UP - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.448289551288331 - 73 - 1 - 44 -1 - 0 -HATCH - 5 -75B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3300.249697062187 - 20 -1257.400104148721 - 11 -3300.249917407054 - 21 -1257.700104148709 - 72 - 1 - 10 -3300.249917407054 - 20 -1257.700104148709 - 11 -3300.553835836938 - 21 -1257.700104148709 - 72 - 1 - 10 -3300.553835836938 - 20 -1257.700104148709 - 11 -3300.249697062187 - 21 -1257.400104148721 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -75C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3300.249697062187 - 20 -1257.400104148721 - 11 -3299.965021637967 - 21 -1257.700104148709 - 72 - 1 - 10 -3299.965021637967 - 20 -1257.700104148709 - 11 -3300.249917407054 - 21 -1257.700104148709 - 72 - 1 - 10 -3300.249917407054 - 20 -1257.700104148709 - 11 -3300.249697062187 - 21 -1257.400104148721 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -75D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3300.553835836938 - 20 -1257.700104148709 - 10 -3300.249697062187 - 20 -1257.400104148721 - 10 -3299.965021634939 - 20 -1257.700104148767 - 10 -3300.553835841363 - 20 -1257.700104148767 - 0 -LWPOLYLINE - 5 -75E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3317.106018910652 - 20 -1255.499554888986 - 10 -3317.106018910652 - 20 -1258.78581493505 - 10 -3316.287334638182 - 20 -1258.78581493505 - 10 -3316.287334638182 - 20 -1257.815531460277 - 0 -LWPOLYLINE - 5 -75F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3316.252986023668 - 20 -1257.300104146532 - 10 -3316.252986023668 - 20 -1255.703955704055 - 0 -MTEXT - 5 -760 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3305.629815684167 - 20 -1241.424159487244 - 30 -0 - 40 -0.21 - 41 -0.3033333333333333 - 71 - 1 - 72 - 5 - 1 -UP - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.448289551288331 - 73 - 1 - 44 -1 - 0 -LINE - 5 -761 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3353.688675249461 - 20 -1259.280104150704 - 11 -3353.918675253634 - 21 -1259.280104150704 - 0 -LINE - 5 -762 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3363.556145619601 - 20 -1249.360104148742 - 11 -3363.556145619601 - 21 -1245.952385825629 - 0 -LINE - 5 -763 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3351.85867524962 - 20 -1243.321229862398 - 11 -3351.85867524962 - 21 -1256.050104161259 - 0 -LINE - 5 -764 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1243.321229862398 - 11 -3352.088675249601 - 21 -1256.050104161259 - 0 -LINE - 5 -765 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3363.32614561962 - 20 -1249.590104148723 - 11 -3363.32614561962 - 21 -1245.952385825629 - 0 -LINE - 5 -766 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1242.252369962691 - 11 -3355.368675249629 - 21 -1242.252369962691 - 0 -LWPOLYLINE - 5 -767 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3351.85867524962 - 20 -1243.321229862398 - 10 -3351.85867524962 - 20 -1241.721707735967 - 10 -3351.85867524962 - 20 -1241.721707735967 - 10 -3352.088675249601 - 20 -1241.721707735967 - 10 -3352.088675249601 - 20 -1243.321229862398 - 0 -LWPOLYLINE - 5 -768 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3360.32614561962 - 20 -1243.923737554054 - 10 -3360.32614561962 - 20 -1242.900966822169 - 10 -3360.32614561962 - 20 -1241.721707735967 - 10 -3352.088675249601 - 20 -1241.721707735967 - 0 -LWPOLYLINE - 5 -769 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3353.688675249461 - 20 -1259.280104150704 - 10 -3353.918675253634 - 20 -1259.280104150704 - 0 -LINE - 5 -76A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288675249554 - 20 -1243.552369962679 - 11 -3353.288675249554 - 21 -1242.352369962667 - 0 -LINE - 5 -76B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1243.852369962668 - 11 -3355.388675249648 - 21 -1243.852369962668 - 0 -LINE - 5 -76C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1244.152369962656 - 11 -3355.388675249648 - 21 -1244.152369962656 - 0 -LINE - 5 -76D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1244.452369962644 - 11 -3355.388675249648 - 21 -1244.452369962644 - 0 -LINE - 5 -76E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1244.752369962691 - 11 -3355.388675249648 - 21 -1244.752369962691 - 0 -LINE - 5 -76F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.338675249601 - 20 -1243.552369962679 - 11 -3355.388675249648 - 21 -1243.552369962679 - 0 -LWPOLYLINE - 5 -770 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3353.288301003864 - 20 -1246.252369962691 - 10 -3353.288301003864 - 20 -1244.152369962656 - 0 -LWPOLYLINE - 5 -771 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3353.288301003864 - 20 -1243.852369962668 - 10 -3353.288301003864 - 20 -1243.552369962679 - 10 -3354.188675249461 - 20 -1243.552369962679 - 10 -3354.188675249461 - 20 -1245.052369962679 - 0 -LWPOLYLINE - 5 -772 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3354.188675249461 - 20 -1245.152369962656 - 10 -3354.188675249461 - 20 -1245.652369962656 - 0 -LINE - 5 -773 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3353.258301003836 - 20 -1246.252369962691 - 11 -3353.258301003836 - 21 -1244.152369962656 - 0 -LINE - 5 -774 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3353.258301003836 - 20 -1243.852369962668 - 11 -3353.258301003836 - 21 -1243.522369962651 - 0 -LINE - 5 -775 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3353.258301003836 - 20 -1243.522369962651 - 11 -3354.21867524949 - 21 -1243.522369962651 - 0 -LINE - 5 -776 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.21867524949 - 20 -1245.052369962679 - 11 -3354.21867524949 - 21 -1245.652369962656 - 0 -LINE - 5 -777 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3353.228301003809 - 20 -1246.252369962691 - 11 -3353.228301003809 - 21 -1244.152369962656 - 0 -LINE - 5 -778 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3353.228301003809 - 20 -1243.852369962668 - 11 -3353.228301003809 - 21 -1243.492369962681 - 0 -LINE - 5 -779 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3353.228301003809 - 20 -1243.492369962681 - 11 -3354.248675249517 - 21 -1243.492369962681 - 0 -LINE - 5 -77A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.248675249517 - 20 -1245.052369962679 - 11 -3354.248675249517 - 21 -1245.652369962656 - 0 -LINE - 5 -77B -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1246.252369962691 - 11 -3353.288301003864 - 21 -1244.752369962691 - 0 -LINE - 5 -77C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3355.388675249648 - 20 -1244.752369962691 - 11 -3355.388675249648 - 21 -1245.052369962679 - 0 -LINE - 5 -77D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1243.852369962668 - 11 -3352.088675249601 - 21 -1243.852369962668 - 0 -LINE - 5 -77E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1243.552369962679 - 11 -3352.088675249601 - 21 -1243.552369962679 - 0 -LINE - 5 -77F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1244.152369962656 - 11 -3352.088675249601 - 21 -1244.152369962656 - 0 -LINE - 5 -780 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1244.452369962644 - 11 -3352.088675249601 - 21 -1244.452369962644 - 0 -LINE - 5 -781 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1244.752369962691 - 11 -3352.088675249601 - 21 -1244.752369962691 - 0 -LINE - 5 -782 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1245.052369962679 - 11 -3352.088675249601 - 21 -1245.052369962679 - 0 -LINE - 5 -783 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1245.352369962667 - 11 -3352.088675249601 - 21 -1245.352369962667 - 0 -LINE - 5 -784 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1245.652369962656 - 11 -3352.088675249601 - 21 -1245.652369962656 - 0 -LINE - 5 -785 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1245.952369962644 - 11 -3352.088675249601 - 21 -1245.952369962644 - 0 -LINE - 5 -786 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1246.252369962691 - 11 -3352.088675249601 - 21 -1246.252369962691 - 0 -LINE - 5 -787 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1243.602689753345 - 11 -3354.188675249461 - 21 -1242.352369962667 - 0 -LINE - 5 -788 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.888675249648 - 20 -1243.552369962679 - 11 -3353.888675249648 - 21 -1242.352369962667 - 0 -LINE - 5 -789 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.588675249601 - 20 -1243.552369962679 - 11 -3353.588675249601 - 21 -1242.352369962667 - 0 -LINE - 5 -78A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3363.32614561962 - 20 -1245.952385825629 - 11 -3363.55765715451 - 21 -1245.952369962644 - 0 -LWPOLYLINE - 5 -78B -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3352.088675249601 - 20 -1242.352369962726 - 10 -3355.418675249442 - 20 -1242.352369962726 - 10 -3355.418675249442 - 20 -1242.722369962663 - 0 -LWPOLYLINE - 5 -78C -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3352.088675249601 - 20 -1242.302369962737 - 10 -3355.468675249489 - 20 -1242.302369962737 - 10 -3355.468675249489 - 20 -1242.722369962663 - 0 -LWPOLYLINE - 5 -78D -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3352.088675249601 - 20 -1242.252369962749 - 10 -3355.518675249536 - 20 -1242.252369962749 - 10 -3355.518675249536 - 20 -1242.722369962663 - 0 -LINE - 5 -78E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1245.052369962679 - 11 -3355.388675249648 - 21 -1245.052369962679 - 0 -LINE - 5 -78F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1245.352369962667 - 11 -3355.388675249648 - 21 -1245.352369962667 - 0 -LINE - 5 -790 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1245.652369962656 - 11 -3355.388675249648 - 21 -1245.652369962656 - 0 -HATCH - 5 -791 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANGLE - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 13 - 72 - 1 - 10 -3363.456145619741 - 20 -1245.238323131401 - 11 -3363.32614561962 - 21 -1245.238323131401 - 72 - 1 - 10 -3363.32614561962 - 20 -1245.238323131401 - 11 -3363.32614561962 - 21 -1245.952802684624 - 72 - 1 - 10 -3363.32614561962 - 20 -1245.952802684624 - 11 -3362.667689515511 - 21 -1245.952802684624 - 72 - 1 - 10 -3362.667689515511 - 20 -1245.952802684624 - 11 -3357.09232120309 - 21 -1245.952802684624 - 72 - 1 - 10 -3357.09232120309 - 20 -1245.952802684624 - 11 -3357.09232120309 - 21 -1245.052802684659 - 72 - 1 - 10 -3357.09232120309 - 20 -1245.052802684659 - 11 -3357.09232120309 - 21 -1244.522369962651 - 72 - 1 - 10 -3357.09232120309 - 20 -1244.522369962651 - 11 -3357.09232120309 - 21 -1243.472369962663 - 72 - 1 - 10 -3357.09232120309 - 20 -1243.472369962663 - 11 -3357.09232120309 - 21 -1243.04620614968 - 72 - 1 - 10 -3357.09232120309 - 20 -1243.04620614968 - 11 -3360.096145619638 - 21 -1243.490785840957 - 72 - 1 - 10 -3360.096145619638 - 20 -1243.490785840957 - 11 -3360.096145619638 - 21 -1243.923737554054 - 72 - 1 - 10 -3360.096145619638 - 20 -1243.923737554054 - 11 -3360.32614561962 - 21 -1243.923737554054 - 72 - 1 - 10 -3360.32614561962 - 20 -1243.923737554054 - 11 -3363.456145619741 - 21 -1243.923737554054 - 72 - 1 - 10 -3363.456145619741 - 20 -1243.923737554054 - 11 -3363.456145619741 - 21 -1245.238323131401 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -1.5 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -HATCH - 5 -792 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3355.617321202998 - 20 -1244.252369962691 - 11 -3355.617321202998 - 21 -1244.752369962691 - 72 - 1 - 10 -3355.617321202998 - 20 -1244.752369962691 - 11 -3355.387321203016 - 21 -1244.752369962691 - 72 - 1 - 10 -3355.387321203016 - 20 -1244.752369962691 - 11 -3355.387321203016 - 21 -1244.252369962691 - 72 - 1 - 10 -3355.387321203016 - 20 -1244.252369962691 - 11 -3355.617321202998 - 21 -1244.252369962691 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -793 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3355.387321203016 - 20 -1244.752369962691 - 10 -3355.617321202998 - 20 -1244.752369962691 - 10 -3355.617321202998 - 20 -1244.252369962691 - 10 -3355.387321203016 - 20 -1244.252369962691 - 10 -3355.387321203016 - 20 -1244.752369962691 - 0 -HATCH - 5 -794 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3352.088675249601 - 20 -1258.780104148725 - 11 -3352.088675249601 - 21 -1259.280104148725 - 72 - 1 - 10 -3352.088675249601 - 20 -1259.280104148725 - 11 -3351.85867524962 - 21 -1259.280104148725 - 72 - 1 - 10 -3351.85867524962 - 20 -1259.280104148725 - 11 -3351.85867524962 - 21 -1258.780104148725 - 72 - 1 - 10 -3351.85867524962 - 20 -1258.780104148725 - 11 -3352.088675249601 - 21 -1258.780104148725 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -795 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3351.85867524962 - 20 -1259.280104148725 - 10 -3352.088675249601 - 20 -1259.280104148725 - 10 -3352.088675249601 - 20 -1258.780104148725 - 10 -3351.85867524962 - 20 -1258.780104148725 - 10 -3351.85867524962 - 20 -1259.280104148725 - 0 -HATCH - 5 -796 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 5 - 72 - 1 - 10 -3355.58732120297 - 20 -1243.623737554066 - 11 -3355.58732120297 - 21 -1243.653737554094 - 72 - 1 - 10 -3355.58732120297 - 20 -1243.653737554094 - 11 -3355.387321203016 - 21 -1243.653737554094 - 72 - 1 - 10 -3355.387321203016 - 20 -1243.653737554094 - 11 -3355.387321203016 - 21 -1243.423737554112 - 72 - 1 - 10 -3355.387321203016 - 20 -1243.423737554112 - 11 -3355.58732120297 - 21 -1243.423737554112 - 72 - 1 - 10 -3355.58732120297 - 20 -1243.423737554112 - 11 -3355.58732120297 - 21 -1243.623737554066 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -797 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3355.58732120297 - 20 -1243.623737554066 - 10 -3355.58732120297 - 20 -1243.423737554112 - 10 -3355.387321203016 - 20 -1243.423737554112 - 10 -3355.387321203016 - 20 -1243.653737554094 - 10 -3355.58732120297 - 20 -1243.653737554094 - 10 -3355.58732120297 - 20 -1243.623737554066 - 0 -HATCH - 5 -798 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 5 - 72 - 1 - 10 -3357.09232120309 - 20 -1243.623737554066 - 11 -3357.09232120309 - 21 -1243.653737554094 - 72 - 1 - 10 -3357.09232120309 - 20 -1243.653737554094 - 11 -3356.892321203137 - 21 -1243.653737554094 - 72 - 1 - 10 -3356.892321203137 - 20 -1243.653737554094 - 11 -3356.892321203137 - 21 -1243.423737554054 - 72 - 1 - 10 -3356.892321203137 - 20 -1243.423737554054 - 11 -3357.09232120309 - 21 -1243.423737554054 - 72 - 1 - 10 -3357.09232120309 - 20 -1243.423737554054 - 11 -3357.09232120309 - 21 -1243.623737554066 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -799 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3357.09232120309 - 20 -1243.623737554066 - 10 -3357.09232120309 - 20 -1243.423737554054 - 10 -3356.892321203137 - 20 -1243.423737554054 - 10 -3356.892321203137 - 20 -1243.653737554094 - 10 -3357.09232120309 - 20 -1243.653737554094 - 10 -3357.09232120309 - 20 -1243.623737554066 - 0 -HATCH - 5 -79A -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3352.358675249619 - 20 -1252.820104148704 - 11 -3351.85867524962 - 21 -1252.820104148704 - 72 - 1 - 10 -3351.85867524962 - 20 -1252.820104148704 - 11 -3351.85867524962 - 21 -1252.590104148723 - 72 - 1 - 10 -3351.85867524962 - 20 -1252.590104148723 - 11 -3352.358675249619 - 21 -1252.590104148723 - 72 - 1 - 10 -3352.358675249619 - 20 -1252.590104148723 - 11 -3352.358675249619 - 21 -1252.820104148704 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -79B -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3351.85867524962 - 20 -1252.590104148723 - 10 -3351.85867524962 - 20 -1252.820104148704 - 10 -3352.358675249619 - 20 -1252.820104148704 - 10 -3352.358675249619 - 20 -1252.590104148723 - 10 -3351.85867524962 - 20 -1252.590104148723 - 0 -HATCH - 5 -79C -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3351.85867524962 - 20 -1246.452369962644 - 11 -3351.85867524962 - 21 -1245.952369962644 - 72 - 1 - 10 -3351.85867524962 - 20 -1245.952369962644 - 11 -3352.088675249601 - 21 -1245.952369962644 - 72 - 1 - 10 -3352.088675249601 - 20 -1245.952369962644 - 11 -3352.088675249601 - 21 -1246.452369962644 - 72 - 1 - 10 -3352.088675249601 - 20 -1246.452369962644 - 11 -3351.85867524962 - 21 -1246.452369962644 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -79D -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3352.088675249601 - 20 -1245.952369962644 - 10 -3351.85867524962 - 20 -1245.952369962644 - 10 -3351.85867524962 - 20 -1246.452369962644 - 10 -3352.088675249601 - 20 -1246.452369962644 - 10 -3352.088675249601 - 20 -1245.952369962644 - 0 -HATCH - 5 -79E -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3363.32614561962 - 20 -1246.452369962644 - 11 -3363.32614561962 - 21 -1245.952369962644 - 72 - 1 - 10 -3363.32614561962 - 20 -1245.952369962644 - 11 -3363.556145619601 - 21 -1245.952369962644 - 72 - 1 - 10 -3363.556145619601 - 20 -1245.952369962644 - 11 -3363.556145619601 - 21 -1246.452369962644 - 72 - 1 - 10 -3363.556145619601 - 20 -1246.452369962644 - 11 -3363.32614561962 - 21 -1246.452369962644 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -79F -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3363.556145619601 - 20 -1245.952369962644 - 10 -3363.32614561962 - 20 -1245.952369962644 - 10 -3363.32614561962 - 20 -1246.452369962644 - 10 -3363.556145619601 - 20 -1246.452369962644 - 10 -3363.556145619601 - 20 -1245.952369962644 - 0 -HATCH - 5 -7A0 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 5 - 72 - 1 - 10 -3357.09232120309 - 20 -1244.722369962663 - 11 -3357.09232120309 - 21 -1244.752369962633 - 72 - 1 - 10 -3357.09232120309 - 20 -1244.752369962633 - 11 -3356.892321203137 - 21 -1244.752369962633 - 72 - 1 - 10 -3356.892321203137 - 20 -1244.752369962633 - 11 -3356.892321203137 - 21 -1244.522369962651 - 72 - 1 - 10 -3356.892321203137 - 20 -1244.522369962651 - 11 -3357.09232120309 - 21 -1244.522369962651 - 72 - 1 - 10 -3357.09232120309 - 20 -1244.522369962651 - 11 -3357.09232120309 - 21 -1244.722369962663 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -7A1 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3357.09232120309 - 20 -1244.722369962663 - 10 -3357.09232120309 - 20 -1244.522369962651 - 10 -3356.892321203137 - 20 -1244.522369962651 - 10 -3356.892321203137 - 20 -1244.752369962633 - 10 -3357.09232120309 - 20 -1244.752369962633 - 10 -3357.09232120309 - 20 -1244.722369962663 - 0 -HATCH - 5 -7A2 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3352.358675249619 - 20 -1249.590104148723 - 11 -3351.85867524962 - 21 -1249.590104148723 - 72 - 1 - 10 -3351.85867524962 - 20 -1249.590104148723 - 11 -3351.85867524962 - 21 -1249.360104148742 - 72 - 1 - 10 -3351.85867524962 - 20 -1249.360104148742 - 11 -3352.358675249619 - 21 -1249.360104148742 - 72 - 1 - 10 -3352.358675249619 - 20 -1249.360104148742 - 11 -3352.358675249619 - 21 -1249.590104148723 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -7A3 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3351.85867524962 - 20 -1249.360104148742 - 10 -3351.85867524962 - 20 -1249.590104148723 - 10 -3352.358675249619 - 20 -1249.590104148723 - 10 -3352.358675249619 - 20 -1249.360104148742 - 10 -3351.85867524962 - 20 -1249.360104148742 - 0 -HATCH - 5 -7A4 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3363.556145619601 - 20 -1249.590104148723 - 11 -3363.056145619601 - 21 -1249.590104148723 - 72 - 1 - 10 -3363.056145619601 - 20 -1249.590104148723 - 11 -3363.056145619601 - 21 -1249.360104148742 - 72 - 1 - 10 -3363.056145619601 - 20 -1249.360104148742 - 11 -3363.556145619601 - 21 -1249.360104148742 - 72 - 1 - 10 -3363.556145619601 - 20 -1249.360104148742 - 11 -3363.556145619601 - 21 -1249.590104148723 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -7A5 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3363.056145619601 - 20 -1249.360104148742 - 10 -3363.056145619601 - 20 -1249.590104148723 - 10 -3363.556145619601 - 20 -1249.590104148723 - 10 -3363.556145619601 - 20 -1249.360104148742 - 10 -3363.056145619601 - 20 -1249.360104148742 - 0 -HATCH - 5 -7A6 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3352.088675249601 - 20 -1242.154635776649 - 11 -3352.088675249601 - 21 -1242.654635776649 - 72 - 1 - 10 -3352.088675249601 - 20 -1242.654635776649 - 11 -3351.85867524962 - 21 -1242.654635776649 - 72 - 1 - 10 -3351.85867524962 - 20 -1242.654635776649 - 11 -3351.85867524962 - 21 -1242.154635776649 - 72 - 1 - 10 -3351.85867524962 - 20 -1242.154635776649 - 11 -3352.088675249601 - 21 -1242.154635776649 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -7A7 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3351.85867524962 - 20 -1242.654635776649 - 10 -3352.088675249601 - 20 -1242.654635776649 - 10 -3352.088675249601 - 20 -1242.154635776649 - 10 -3351.85867524962 - 20 -1242.154635776649 - 10 -3351.85867524962 - 20 -1242.654635776649 - 0 -HATCH - 5 -7A8 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3351.85867524962 - 20 -1256.050104161259 - 11 -3351.85867524962 - 21 -1255.550104161259 - 72 - 1 - 10 -3351.85867524962 - 20 -1255.550104161259 - 11 -3352.088675249601 - 21 -1255.550104161259 - 72 - 1 - 10 -3352.088675249601 - 20 -1255.550104161259 - 11 -3352.088675249601 - 21 -1256.050104161259 - 72 - 1 - 10 -3352.088675249601 - 20 -1256.050104161259 - 11 -3351.85867524962 - 21 -1256.050104161259 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -7A9 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3352.088675249601 - 20 -1255.550104161259 - 10 -3351.85867524962 - 20 -1255.550104161259 - 10 -3351.85867524962 - 20 -1256.050104161259 - 10 -3352.088675249601 - 20 -1256.050104161259 - 10 -3352.088675249601 - 20 -1255.550104161259 - 0 -LWPOLYLINE - 5 -7AA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3360.096145619638 - 20 -1243.823737554077 - 10 -3363.556145619601 - 20 -1243.823737554077 - 10 -3363.556145619601 - 20 -1245.238323131401 - 0 -LWPOLYLINE - 5 -7AB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3363.55765715451 - 20 -1245.952369962644 - 10 -3363.556145619601 - 20 -1245.238323131401 - 10 -3363.32614561962 - 20 -1245.238323131401 - 10 -3363.32614561962 - 20 -1245.952385825629 - 0 -LINE - 5 -7AC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3355.617321202998 - 20 -1244.402369962656 - 11 -3355.617321202998 - 21 -1244.445176272304 - 0 -LINE - 5 -7AD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3355.617321202998 - 20 -1244.48176036129 - 11 -3355.617321202998 - 21 -1244.52456667088 - 0 -LINE - 5 -7AE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 52 -370 - 0 -100 -AcDbLine - 10 -3356.892321203137 - 20 -1244.402369962656 - 11 -3356.892321203137 - 21 -1243.472369962663 - 0 -LINE - 5 -7AF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3356.892321203137 - 20 -1244.552369962679 - 11 -3356.740498226369 - 21 -1244.552369962679 - 0 -LINE - 5 -7B0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3355.740498226369 - 20 -1244.552369962679 - 11 -3355.617321202998 - 21 -1244.552369962679 - 0 -LINE - 5 -7B1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3356.892321203137 - 20 -1244.752369962633 - 11 -3356.740498226369 - 21 -1244.752369962633 - 0 -LINE - 5 -7B2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3355.740498226369 - 20 -1244.752369962691 - 11 -3355.388675249648 - 21 -1244.752369962691 - 0 -LINE - 5 -7B3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3355.617321202998 - 20 -1244.402369962656 - 11 -3355.617321202998 - 21 -1244.445176272304 - 0 -LINE - 5 -7B4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3355.617321202998 - 20 -1244.48176036129 - 11 -3355.617321202998 - 21 -1244.52456667088 - 0 -LWPOLYLINE - 5 -7B5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbPolyline - 90 - 8 - 70 - 0 - 43 -0 - 10 -3356.892321203137 - 20 -1243.472369962663 - 10 -3356.892321203137 - 20 -1244.752369962633 - 10 -3357.09232120309 - 20 -1244.752369962633 - 10 -3357.092321204488 - 20 -1244.752369964204 - 10 -3357.092321204488 - 20 -1244.522369963757 - 10 -3357.092321204488 - 20 -1244.522369963757 - 10 -3357.09232120309 - 20 -1243.472369962663 - 10 -3356.892321203137 - 20 -1243.472369962663 - 0 -LINE - 5 -7B6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3355.388675249648 - 20 -1243.472369962663 - 11 -3355.388675249648 - 21 -1244.752369962691 - 0 -LINE - 5 -7B7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3355.588675249601 - 20 -1243.672369962675 - 11 -3355.588675249601 - 21 -1244.252369962691 - 0 -LWPOLYLINE - 5 -7B8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3355.58732120297 - 20 -1243.472369962663 - 10 -3355.388675249648 - 20 -1243.472369962663 - 10 -3355.388675249648 - 20 -1242.722369962663 - 10 -3355.388675249648 - 20 -1242.722369962663 - 0 -LINE - 5 -7B9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3355.740498226369 - 20 -1244.552369962679 - 11 -3355.740498226369 - 21 -1244.752369962691 - 0 -LINE - 5 -7BA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3356.740498226369 - 20 -1244.552369962679 - 11 -3356.740498226369 - 21 -1244.752369962633 - 0 -LWPOLYLINE - 5 -7BB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 1 - 43 -0 - 10 -3355.667321203044 - 20 -1244.502369962691 - 10 -3356.84232120309 - 20 -1244.502369962691 - 10 -3356.84232120309 - 20 -1242.972369962663 - 10 -3355.637321203016 - 20 -1242.972369962663 - 10 -3355.637321203016 - 20 -1244.202369962644 - 10 -3355.667321203044 - 20 -1244.202369962644 - 0 -LWPOLYLINE - 5 -7BC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 1 - 43 -0 - 10 -3355.717321203091 - 20 -1244.452369962644 - 10 -3356.792321203044 - 20 -1244.452369962644 - 10 -3356.792321203044 - 20 -1243.022369962651 - 10 -3355.687321203062 - 20 -1243.022369962651 - 10 -3355.687321203062 - 20 -1244.152369962656 - 10 -3355.717321203091 - 20 -1244.152369962656 - 0 -LINE - 5 -7BD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3355.617321202998 - 20 -1244.552369962679 - 11 -3356.892321203137 - 21 -1242.922369962675 - 0 -LINE - 5 -7BE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3356.892321203137 - 20 -1244.552369962679 - 11 -3355.58732120297 - 21 -1242.922369962675 - 0 -MTEXT - 5 -7BF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3355.895680091343 - 20 -1243.275681681291 - 30 -0 - 40 -0.21 - 41 -0.5133333333333333 - 71 - 1 - 72 - 5 - 1 -LIFT - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -7C0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3356.264822534053 - 20 -1243.303355389158 - 30 -0 - 40 -0.21 - 41 -1.026666666666706 - 71 - 1 - 72 - 5 - 1 -163X130 - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -LINE - 5 -7C1 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3355.387321203016 - 20 -1244.752369962691 - 11 -3355.388675249648 - 21 -1245.052369962679 - 0 -LWPOLYLINE - 5 -7C2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3355.58732120297 - 20 -1243.423737554112 - 10 -3355.58732120297 - 20 -1242.722369962663 - 10 -3355.388675249648 - 20 -1242.722369962663 - 10 -3355.388675249648 - 20 -1243.423737554112 - 0 -HATCH - 5 -7C3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3352.6887084716 - 20 -1243.852369962668 - 11 -3352.688928816468 - 21 -1243.552369962679 - 72 - 1 - 10 -3352.688928816468 - 20 -1243.552369962679 - 11 -3352.992847246583 - 21 -1243.552369962679 - 72 - 1 - 10 -3352.992847246583 - 20 -1243.552369962679 - 11 -3352.6887084716 - 21 -1243.852369962668 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -7C4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3352.6887084716 - 20 -1243.852369962668 - 11 -3352.404033047613 - 21 -1243.552369962679 - 72 - 1 - 10 -3352.404033047613 - 20 -1243.552369962679 - 11 -3352.688928816468 - 21 -1243.552369962679 - 72 - 1 - 10 -3352.688928816468 - 20 -1243.552369962679 - 11 -3352.6887084716 - 21 -1243.852369962668 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -7C5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3354.802367591999 - 20 -1246.567925359879 - 10 -3354.802367591999 - 20 -1243.552369962679 - 10 -3354.802367591999 - 20 -1242.922737527056 - 10 -3352.689391270746 - 20 -1242.922737527056 - 10 -3352.688488126732 - 20 -1244.152369962656 - 0 -LWPOLYLINE - 5 -7C6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3352.992847246583 - 20 -1243.552369962679 - 10 -3352.6887084716 - 20 -1243.852369962668 - 10 -3352.404033047613 - 20 -1243.552369962679 - 10 -3352.992847246583 - 20 -1243.552369962679 - 0 -LWPOLYLINE - 5 -7C7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3354.21867524949 - 20 -1243.492369962681 - 10 -3354.21867524949 - 20 -1245.402369962656 - 10 -3353.258301003836 - 20 -1245.402369962656 - 0 -LWPOLYLINE - 5 -7C8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3354.248675249517 - 20 -1243.492369962681 - 10 -3354.248675249517 - 20 -1245.452369962644 - 10 -3353.258301003836 - 20 -1245.452369962644 - 0 -LINE - 5 -7C9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3355.388675249648 - 20 -1245.052369962679 - 11 -3355.388675249648 - 21 -1245.652369962656 - 0 -LWPOLYLINE - 5 -7CA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3355.387321203016 - 20 -1244.752369962691 - 10 -3355.388675249648 - 20 -1245.052369962679 - 0 -LWPOLYLINE - 5 -7CB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3355.437320693862 - 20 -1244.752144290542 - 10 -3355.43867474026 - 20 -1245.05214429053 - 0 -LWPOLYLINE - 5 -7CC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3355.487320184476 - 20 -1244.751918618451 - 10 -3355.488674230874 - 20 -1245.051918618439 - 0 -LWPOLYLINE - 5 -7CD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3355.388675249648 - 20 -1245.052369962679 - 10 -3355.488674230874 - 20 -1245.051918618439 - 0 -LINE - 5 -7CE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1256.300104148744 - 11 -3352.838675249601 - 21 -1256.300104148744 - 0 -LINE - 5 -7CF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1256.500104148756 - 11 -3352.838675249601 - 21 -1256.500104148756 - 0 -LINE - 5 -7D0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1256.700104148709 - 11 -3352.838675249601 - 21 -1256.700104148709 - 0 -LINE - 5 -7D1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1256.900104148721 - 11 -3352.838675249601 - 21 -1256.900104148721 - 0 -LINE - 5 -7D2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1257.100104148732 - 11 -3352.838675249601 - 21 -1257.100104148732 - 0 -LINE - 5 -7D3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1257.300104148744 - 11 -3352.838675249601 - 21 -1257.300104148744 - 0 -LINE - 5 -7D4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1257.500104148756 - 11 -3352.838675249601 - 21 -1257.500104148756 - 0 -LINE - 5 -7D5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1257.700104148709 - 11 -3352.838675249601 - 21 -1257.700104148709 - 0 -LINE - 5 -7D6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1257.900104148721 - 11 -3352.838675249601 - 21 -1257.900104148721 - 0 -LINE - 5 -7D7 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1258.100104148732 - 11 -3352.838675249601 - 21 -1258.100104148732 - 0 -LINE - 5 -7D8 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1258.300104148744 - 11 -3352.838675249601 - 21 -1258.300104148744 - 0 -LWPOLYLINE - 5 -7D9 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3352.838675249601 - 20 -1258.300104148744 - 10 -3352.838675249601 - 20 -1258.100104148732 - 0 -LWPOLYLINE - 5 -7DA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3352.838675249601 - 20 -1257.900104148721 - 10 -3352.838675249601 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -7DB -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3352.938675249461 - 20 -1258.300104148744 - 10 -3352.938675249461 - 20 -1256.300104148744 - 0 -LINE - 5 -7DC -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1256.300104148744 - 11 -3353.688675249461 - 21 -1256.300104148744 - 0 -LINE - 5 -7DD -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1256.500104148756 - 11 -3353.688675249461 - 21 -1256.500104148756 - 0 -LINE - 5 -7DE -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1256.700104148709 - 11 -3353.688675249461 - 21 -1256.700104148709 - 0 -LINE - 5 -7DF -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1256.900104148721 - 11 -3353.688675249461 - 21 -1256.900104148721 - 0 -LINE - 5 -7E0 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1257.100104148732 - 11 -3353.688675249461 - 21 -1257.100104148732 - 0 -LINE - 5 -7E1 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1257.300104148744 - 11 -3353.688675249461 - 21 -1257.300104148744 - 0 -LINE - 5 -7E2 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1257.500104148756 - 11 -3353.688675249461 - 21 -1257.500104148756 - 0 -LINE - 5 -7E3 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1257.700104148709 - 11 -3353.688675249461 - 21 -1257.700104148709 - 0 -LINE - 5 -7E4 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1257.900104148721 - 11 -3353.688675249461 - 21 -1257.900104148721 - 0 -LINE - 5 -7E5 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1258.100104148732 - 11 -3353.688675249461 - 21 -1258.100104148732 - 0 -LINE - 5 -7E6 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1258.300104148744 - 11 -3353.688675249461 - 21 -1258.300104148744 - 0 -LWPOLYLINE - 5 -7E7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3353.688675249461 - 20 -1259.050104148744 - 10 -3353.688675249461 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -7E8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3352.838675249601 - 20 -1256.300104148744 - 10 -3352.838675249601 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -7E9 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3352.838675249601 - 20 -1258.100104148732 - 10 -3352.838675249601 - 20 -1258.300104148744 - 10 -3352.938675249461 - 20 -1258.300104148744 - 10 -3352.938675249461 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -7EA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3352.808675249573 - 20 -1256.300104148744 - 10 -3352.808675249573 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -7EB -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3352.808675249573 - 20 -1258.100104148732 - 10 -3352.808675249573 - 20 -1258.330104148714 - 10 -3352.968675249489 - 20 -1258.330104148714 - 10 -3352.968675249489 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -7EC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3352.778675249545 - 20 -1256.300104148744 - 10 -3352.778675249545 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -7ED -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3352.778675249545 - 20 -1258.100104148732 - 10 -3352.778675249545 - 20 -1258.360104148741 - 10 -3352.998675249518 - 20 -1258.360104148741 - 10 -3352.998675249518 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -7EE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3353.688675249461 - 20 -1255.998735667846 - 10 -3353.688675249461 - 20 -1259.280104150704 - 0 -LWPOLYLINE - 5 -7EF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3351.85867524962 - 20 -1256.050104161259 - 10 -3351.858675251249 - 20 -1259.280104150704 - 10 -3353.688675249461 - 20 -1259.280104150704 - 0 -LWPOLYLINE - 5 -7F0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3351.908675249666 - 20 -1256.050104161259 - 10 -3351.908675249666 - 20 -1259.230104148737 - 10 -3353.688675249461 - 20 -1259.230104148737 - 0 -LWPOLYLINE - 5 -7F1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3351.95867524948 - 20 -1256.050104161259 - 10 -3351.95867524948 - 20 -1259.180104148749 - 10 -3353.688675249461 - 20 -1259.180104148749 - 0 -LWPOLYLINE - 5 -7F2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3352.088675249601 - 20 -1256.050104161259 - 10 -3352.088675249601 - 20 -1259.050104148744 - 10 -3353.688675249461 - 20 -1259.050104148744 - 0 -LINE - 5 -7F3 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3357.09232120309 - 20 -1243.423737554054 - 11 -3357.09232120309 - 21 -1243.04620614968 - 0 -LINE - 5 -7F4 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3357.042321203044 - 20 -1243.423737554054 - 11 -3357.042321203044 - 21 -1243.04620614968 - 0 -LINE - 5 -7F5 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3356.992321202997 - 20 -1243.423737554054 - 11 -3356.992321202997 - 21 -1243.04620614968 - 0 -LINE - 5 -7F6 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3356.892321203137 - 20 -1243.423737554054 - 11 -3356.892321203137 - 21 -1243.016605238954 - 0 -LWPOLYLINE - 5 -7F7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3353.918675249442 - 20 -1259.280104148725 - 10 -3353.918675253634 - 20 -1249.590104149363 - 10 -3354.905542837922 - 20 -1249.590104149363 - 0 -LWPOLYLINE - 5 -7F8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3356.105542842066 - 20 -1249.590104148723 - 10 -3357.322410434719 - 20 -1249.590104148723 - 0 -LWPOLYLINE - 5 -7F9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3358.522410434672 - 20 -1249.590104148723 - 10 -3359.73927802709 - 20 -1249.590104148723 - 0 -LWPOLYLINE - 5 -7FA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3360.939278027043 - 20 -1249.590104148723 - 10 -3362.156145619695 - 20 -1249.590104148723 - 0 -LWPOLYLINE - 5 -7FB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3363.056145619601 - 20 -1249.590104148723 - 10 -3363.546145619592 - 20 -1249.590104148723 - 0 -LWPOLYLINE - 5 -7FC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3353.688675249461 - 20 -1255.998735667439 - 10 -3353.688675249461 - 20 -1249.360104148742 - 10 -3354.905542842113 - 20 -1249.360104148742 - 0 -LWPOLYLINE - 5 -7FD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3356.105542842066 - 20 -1249.360104148742 - 10 -3357.322410434719 - 20 -1249.360104148742 - 0 -LWPOLYLINE - 5 -7FE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3358.522410434672 - 20 -1249.360104148742 - 10 -3359.73927802709 - 20 -1249.360104148742 - 0 -LWPOLYLINE - 5 -7FF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3360.939278027043 - 20 -1249.360104148742 - 10 -3362.156145619695 - 20 -1249.360104148742 - 0 -LWPOLYLINE - 5 -800 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3363.056145619601 - 20 -1249.360104148742 - 10 -3363.54677788401 - 20 -1249.360104148742 - 0 -LWPOLYLINE - 5 -801 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3353.918675249442 - 20 -1259.280104148725 - 10 -3363.556145619601 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -802 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3363.556145619601 - 20 -1249.590104148723 - 10 -3363.556145619601 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -803 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3357.092321204488 - 20 -1244.522369963757 - 10 -3357.092321204488 - 20 -1245.052802683494 - 0 -LWPOLYLINE - 5 -804 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3357.092321204488 - 20 -1245.952802682004 - 10 -3357.750777306501 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -805 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3358.950777309481 - 20 -1245.952802682004 - 10 -3359.609233411495 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -806 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3360.809233414475 - 20 -1245.952802682004 - 10 -3361.467689516488 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -807 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3362.667689512019 - 20 -1245.952802682004 - 10 -3363.326145621484 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -808 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3356.862321200315 - 20 -1244.522369963757 - 10 -3356.862321200315 - 20 -1245.052802683494 - 0 -LWPOLYLINE - 5 -809 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3356.862321203109 - 20 -1245.952802684624 - 10 -3356.862321200315 - 20 -1246.182802682451 - 10 -3357.750777306501 - 20 -1246.182802682451 - 0 -LWPOLYLINE - 5 -80A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3358.950777309481 - 20 -1246.182802682451 - 10 -3359.609233411495 - 20 -1246.182802682451 - 0 -LWPOLYLINE - 5 -80B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3360.809233414475 - 20 -1246.182802682451 - 10 -3361.467689516488 - 20 -1246.182802682451 - 0 -LWPOLYLINE - 5 -80C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3362.667689512019 - 20 -1246.182802682451 - 10 -3363.326145621484 - 20 -1246.182802682451 - 0 -LINE - 5 -80D -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.566810790218 - 20 -1240.067414091492 - 11 -3352.566810790218 - 21 -1260.721494615893 - 0 -CIRCLE - 5 -80E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3352.566810790218 - 20 -1241.147899743053 - 40 -0.3105759447073808 - 0 -HATCH - 5 -80F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3352.877386735054 - 20 -1241.147899743053 - 11 -3352.566810790218 - 21 -1241.458475687774 - 72 - 1 - 10 -3352.566810790218 - 20 -1241.458475687774 - 11 -3352.566810790218 - 21 -1240.837323798332 - 72 - 1 - 10 -3352.566810790218 - 20 -1240.837323798332 - 11 -3352.877386735054 - 21 -1241.147899743053 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -810 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3352.566810790218 - 20 -1240.837323797925 - 10 -3352.877386735287 - 20 -1241.147899742995 - 10 -3352.566810790218 - 20 -1241.458475687774 - 10 -3352.566810790218 - 20 -1240.837323797925 - 0 -MTEXT - 5 -811 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3352.852777876891 - 20 -1241.193436495552 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -CIRCLE - 5 -812 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3352.566810790218 - 20 -1260.305064084648 - 40 -0.3105759447073808 - 0 -HATCH - 5 -813 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3352.877386735054 - 20 -1260.305064084648 - 11 -3352.566810790218 - 21 -1260.615640029369 - 72 - 1 - 10 -3352.566810790218 - 20 -1260.615640029369 - 11 -3352.566810790218 - 21 -1259.994488139986 - 72 - 1 - 10 -3352.566810790218 - 20 -1259.994488139986 - 11 -3352.877386735054 - 21 -1260.305064084648 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -814 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3352.566810790218 - 20 -1259.994488139753 - 10 -3352.877386735054 - 20 -1260.305064084648 - 10 -3352.566810790218 - 20 -1260.615640029369 - 10 -3352.566810790218 - 20 -1259.994488139753 - 0 -MTEXT - 5 -815 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3352.852777876891 - 20 -1260.350600837148 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -816 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3353.918675253634 - 20 -1259.280104150704 - 10 -3363.556145618204 - 20 -1259.280104150704 - 10 -3363.556145618204 - 20 -1249.590104149363 - 0 -LWPOLYLINE - 5 -817 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3353.918675249442 - 20 -1259.180104148749 - 10 -3363.456145619741 - 20 -1259.180104148749 - 10 -3363.456145619741 - 20 -1249.590104148723 - 0 -LWPOLYLINE - 5 -818 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3357.09232120309 - 20 -1243.472369962663 - 10 -3357.09232120309 - 20 -1242.722369962663 - 10 -3355.58732120297 - 20 -1242.722369962663 - 0 -LWPOLYLINE - 5 -819 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3356.892321203137 - 20 -1243.472369962663 - 10 -3356.892321203137 - 20 -1242.922369962675 - 10 -3355.58732120297 - 20 -1242.922369962675 - 0 -LWPOLYLINE - 5 -81A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3357.042321203044 - 20 -1243.472369962663 - 10 -3357.042321203044 - 20 -1242.772369962651 - 10 -3355.58732120297 - 20 -1242.772369962651 - 0 -LWPOLYLINE - 5 -81B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3356.992321202997 - 20 -1243.472369962663 - 10 -3356.992321202997 - 20 -1242.822369962639 - 10 -3355.58732120297 - 20 -1242.822369962639 - 0 -LINE - 5 -81C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3359.609233411495 - 20 -1245.952802682004 - 11 -3359.609233411495 - 21 -1246.182802682451 - 0 -LINE - 5 -81D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3360.809233414475 - 20 -1245.952802682004 - 11 -3360.809233414475 - 21 -1246.182802682451 - 0 -LINE - 5 -81E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3362.667689512019 - 20 -1245.952802682004 - 11 -3362.667689512019 - 21 -1246.182802682451 - 0 -LINE - 5 -81F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3361.467689516488 - 20 -1245.952802682004 - 11 -3361.467689516488 - 21 -1246.182802682451 - 0 -LINE - 5 -820 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3358.950777309481 - 20 -1245.952802682004 - 11 -3358.950777309481 - 21 -1246.182802682451 - 0 -LINE - 5 -821 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3357.750777306501 - 20 -1245.952802682004 - 11 -3357.750777306501 - 21 -1246.182802682451 - 0 -LINE - 5 -822 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3357.092321204488 - 20 -1245.952802682004 - 11 -3356.862321200315 - 21 -1245.952802682004 - 0 -LINE - 5 -823 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3357.092321204488 - 20 -1245.052802683494 - 11 -3356.862321200315 - 21 -1245.052802683494 - 0 -LINE - 5 -824 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3363.056145618204 - 20 -1249.360104148916 - 11 -3363.056145618204 - 21 -1249.590104149363 - 0 -LINE - 5 -825 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3362.156145619695 - 20 -1249.360104148742 - 11 -3362.156145619695 - 21 -1249.590104148723 - 0 -LWPOLYLINE - 5 -826 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3357.09232120309 - 20 -1245.052802684659 - 10 -3357.092321204488 - 20 -1245.952802682004 - 10 -3362.667689512019 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -827 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3319.37663197564 - 20 -1242.722369962663 - 10 -3324.115456392291 - 20 -1243.423737554054 - 10 -3324.115456392291 - 20 -1243.823737554077 - 10 -3327.345456392271 - 20 -1243.823737554077 - 10 -3327.345456392271 - 20 -1245.238323131343 - 0 -LWPOLYLINE - 5 -828 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3357.09232120309 - 20 -1242.945116815506 - 10 -3360.326145621483 - 20 -1243.423737553589 - 10 -3360.326145621483 - 20 -1243.823737552098 - 10 -3363.556145618204 - 20 -1243.823737552098 - 10 -3363.556145618204 - 20 -1245.238323131285 - 0 -LWPOLYLINE - 5 -829 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3357.09232120309 - 20 -1243.04620614968 - 10 -3360.226145619761 - 20 -1243.510026432865 - 10 -3360.226145619761 - 20 -1243.923737554054 - 10 -3363.456145619741 - 20 -1243.923737554054 - 10 -3363.456145619741 - 20 -1245.238323131343 - 0 -LINE - 5 -82A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3357.750777306501 - 20 -1246.182802682451 - 11 -3358.950777309481 - 21 -1246.182802682451 - 0 -LINE - 5 -82B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3357.750777306501 - 20 -1245.952802682004 - 11 -3358.950777309481 - 21 -1245.952802682004 - 0 -LINE - 5 -82C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3357.750777307199 - 20 -1246.132802684617 - 11 -3358.950777307153 - 21 -1246.132802684617 - 0 -LINE - 5 -82D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3357.750777307199 - 20 -1246.082802684628 - 11 -3358.950777307153 - 21 -1246.082802684628 - 0 -LINE - 5 -82E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3360.809233414475 - 20 -1245.952802682004 - 11 -3360.809233414475 - 21 -1246.182802682451 - 0 -LINE - 5 -82F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3359.609233411495 - 20 -1245.952802682004 - 11 -3359.609233411495 - 21 -1246.182802682451 - 0 -LINE - 5 -830 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3359.609233411495 - 20 -1246.182802682451 - 11 -3360.809233414475 - 21 -1246.182802682451 - 0 -LINE - 5 -831 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3359.609233411495 - 20 -1245.952802682004 - 11 -3360.809233414475 - 21 -1245.952802682004 - 0 -LINE - 5 -832 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3359.609233411263 - 20 -1246.132802684617 - 11 -3360.809233411448 - 21 -1246.132802684617 - 0 -LINE - 5 -833 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3359.609233411263 - 20 -1246.082802684628 - 11 -3360.809233411448 - 21 -1246.082802684628 - 0 -LINE - 5 -834 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3362.667689512019 - 20 -1245.952802682004 - 11 -3362.667689512019 - 21 -1246.182802682451 - 0 -LINE - 5 -835 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3361.467689516488 - 20 -1245.952802682004 - 11 -3361.467689516488 - 21 -1246.182802682451 - 0 -LINE - 5 -836 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3361.467689516488 - 20 -1246.182802682451 - 11 -3362.667689512019 - 21 -1246.182802682451 - 0 -LINE - 5 -837 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3361.467689516488 - 20 -1245.952802682004 - 11 -3362.667689512019 - 21 -1245.952802682004 - 0 -LINE - 5 -838 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3361.467689515557 - 20 -1246.132802684617 - 11 -3362.667689515511 - 21 -1246.132802684617 - 0 -LINE - 5 -839 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3361.467689515557 - 20 -1246.082802684628 - 11 -3362.667689515511 - 21 -1246.082802684628 - 0 -LWPOLYLINE - 5 -83A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3362.667689512019 - 20 -1245.952802682004 - 10 -3362.667689512019 - 20 -1245.352802684239 - 10 -3362.767689513508 - 20 -1245.352802684239 - 10 -3362.767689513508 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -83B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3361.367689514999 - 20 -1245.952802682004 - 10 -3361.367689514999 - 20 -1245.352802684239 - 10 -3361.467689516488 - 20 -1245.352802684239 - 10 -3361.467689516488 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -83C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3360.809233414475 - 20 -1245.952802682004 - 10 -3360.809233414475 - 20 -1245.352802684239 - 10 -3360.909233415965 - 20 -1245.352802684239 - 10 -3360.909233415965 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -83D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3359.509233417455 - 20 -1245.952802682004 - 10 -3359.509233417455 - 20 -1245.352802684239 - 10 -3359.609233411495 - 20 -1245.352802684239 - 10 -3359.609233411495 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -83E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3358.950777309481 - 20 -1245.952802682004 - 10 -3358.950777309481 - 20 -1245.352802684239 - 10 -3359.050777310971 - 20 -1245.352802684239 - 10 -3359.050777310971 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -83F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3357.650777305011 - 20 -1245.952802682004 - 10 -3357.650777305011 - 20 -1245.352802684239 - 10 -3357.750777306501 - 20 -1245.352802684239 - 10 -3357.750777306501 - 20 -1245.952802682004 - 0 -LINE - 5 -840 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3358.522410434672 - 20 -1249.360104148742 - 11 -3358.522410434672 - 21 -1249.590104148723 - 0 -LINE - 5 -841 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3357.322410434719 - 20 -1249.360104148742 - 11 -3357.322410434719 - 21 -1249.590104148723 - 0 -LINE - 5 -842 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3360.939278027043 - 20 -1249.360104148742 - 11 -3360.939278027043 - 21 -1249.590104148723 - 0 -LINE - 5 -843 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3359.73927802709 - 20 -1249.360104148742 - 11 -3359.73927802709 - 21 -1249.590104148723 - 0 -LINE - 5 -844 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3356.105542842066 - 20 -1249.360104148742 - 11 -3356.105542842066 - 21 -1249.590104148723 - 0 -LINE - 5 -845 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3354.905542837922 - 20 -1249.360104148916 - 11 -3354.905542837922 - 21 -1249.590104149363 - 0 -LINE - 5 -846 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3354.905542842113 - 20 -1249.590104148723 - 11 -3363.556145619601 - 21 -1249.590104148723 - 0 -HATCH - 5 -847 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3353.918675249442 - 20 -1258.780104148725 - 11 -3353.918675249442 - 21 -1259.280104148725 - 72 - 1 - 10 -3353.918675249442 - 20 -1259.280104148725 - 11 -3353.688675249461 - 21 -1259.280104148725 - 72 - 1 - 10 -3353.688675249461 - 20 -1259.280104148725 - 11 -3353.688675249461 - 21 -1258.780104148725 - 72 - 1 - 10 -3353.688675249461 - 20 -1258.780104148725 - 11 -3353.918675249442 - 21 -1258.780104148725 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -848 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3353.688675249461 - 20 -1259.280104150704 - 10 -3353.918675253634 - 20 -1259.280104150704 - 10 -3353.918675249442 - 20 -1258.780104148725 - 10 -3353.688675249461 - 20 -1258.780104150704 - 10 -3353.688675249461 - 20 -1259.280104150704 - 0 -HATCH - 5 -849 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3353.688675249461 - 20 -1256.050104161259 - 11 -3353.688675249461 - 21 -1255.550104161259 - 72 - 1 - 10 -3353.688675249461 - 20 -1255.550104161259 - 11 -3353.918675249442 - 21 -1255.550104161259 - 72 - 1 - 10 -3353.918675249442 - 20 -1255.550104161259 - 11 -3353.918675249442 - 21 -1256.050104161259 - 72 - 1 - 10 -3353.918675249442 - 20 -1256.050104161259 - 11 -3353.688675249461 - 21 -1256.050104161259 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -84A -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3353.918675249442 - 20 -1255.550104161259 - 10 -3353.688675249461 - 20 -1255.550104161259 - 10 -3353.688675249461 - 20 -1256.050104161259 - 10 -3353.918675249442 - 20 -1256.050104161259 - 10 -3353.918675249442 - 20 -1255.550104161259 - 0 -HATCH - 5 -84B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANGLE - 70 - 0 - 71 - 0 - 91 - 2 - 92 - 0 - 93 - 6 - 72 - 1 - 10 -3363.456145619741 - 20 -1259.180104148749 - 11 -3353.918675249442 - 21 -1259.180104148749 - 72 - 1 - 10 -3353.918675249442 - 20 -1259.180104148749 - 11 -3353.918675249442 - 21 -1258.780104148725 - 72 - 1 - 10 -3353.918675249442 - 20 -1258.780104148725 - 11 -3353.918675249442 - 21 -1249.590104148723 - 72 - 1 - 10 -3353.918675249442 - 20 -1249.590104148723 - 11 -3354.905542842113 - 21 -1249.590104148723 - 72 - 1 - 10 -3354.905542842113 - 20 -1249.590104148723 - 11 -3363.456145619741 - 21 -1249.590104148723 - 72 - 1 - 10 -3363.456145619741 - 20 -1249.590104148723 - 11 -3363.456145619741 - 21 -1259.180104148749 - 97 - 0 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3355.355586569291 - 20 -1252.165106727509 - 11 -3360.934950756609 - 21 -1252.121452173392 - 72 - 1 - 10 -3360.934950756609 - 20 -1252.121452173392 - 11 -3360.943136016139 - 21 -1253.167586872005 - 72 - 1 - 10 -3360.943136016139 - 20 -1253.167586871947 - 11 -3355.363771828824 - 21 -1253.211241426062 - 72 - 1 - 10 -3355.363771828824 - 20 -1253.211241426062 - 11 -3355.355586569291 - 21 -1252.16510672745 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -1.5 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -MTEXT - 5 -84C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3355.512360998429 - 20 -1252.932892533427 - 30 -0 - 40 -0.4900000000000003 - 41 -4.831944444444448 - 71 - 1 - 72 - 5 - 1 -OPEN TERRACE - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LINE - 5 -84D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3374.172164166812 - 20 -1259.280104150704 - 11 -3374.402164170984 - 21 -1259.280104150704 - 0 -LINE - 5 -84E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3372.342164165108 - 20 -1243.321229862398 - 11 -3372.342164165108 - 21 -1256.050104161259 - 0 -LINE - 5 -84F -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3372.572164165323 - 20 -1242.252369960479 - 11 -3375.852164166514 - 21 -1242.252369960479 - 0 -LWPOLYLINE - 5 -850 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3380.809634535341 - 20 -1243.923737554054 - 10 -3380.809634535341 - 20 -1242.900966822169 - 10 -3380.809634535341 - 20 -1241.721707735967 - 10 -3372.572164165323 - 20 -1241.721707735967 - 0 -LWPOLYLINE - 5 -851 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3374.172164166812 - 20 -1259.280104150704 - 10 -3374.402164170984 - 20 -1259.280104150704 - 0 -HATCH - 5 -852 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANGLE - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 9 - 72 - 1 - 10 -3383.939634535229 - 20 -1245.238323131401 - 11 -3377.575810118579 - 21 -1245.238323131401 - 72 - 1 - 10 -3377.575810118579 - 20 -1245.238323131401 - 11 -3377.575810118579 - 21 -1244.522369962651 - 72 - 1 - 10 -3377.575810118579 - 20 -1244.522369962651 - 11 -3377.575810118579 - 21 -1243.472369962663 - 72 - 1 - 10 -3377.575810118579 - 20 -1243.472369962663 - 11 -3377.575810118579 - 21 -1243.04620614968 - 72 - 1 - 10 -3377.575810118579 - 20 -1243.04620614968 - 11 -3380.579634535126 - 21 -1243.490785840957 - 72 - 1 - 10 -3380.579634535358 - 20 -1243.490785840957 - 11 -3380.579634535358 - 21 -1243.923737554112 - 72 - 1 - 10 -3380.579634535358 - 20 -1243.923737554054 - 11 -3380.809634535341 - 21 -1243.923737554054 - 72 - 1 - 10 -3380.809634535341 - 20 -1243.923737554054 - 11 -3383.939634535229 - 21 -1243.923737554054 - 72 - 1 - 10 -3383.939634535229 - 20 -1243.923737554054 - 11 -3383.939634535229 - 21 -1245.238323131343 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -1.5 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -HATCH - 5 -853 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3372.572164165089 - 20 -1258.780104148725 - 11 -3372.572164165089 - 21 -1259.280104148725 - 72 - 1 - 10 -3372.572164165089 - 20 -1259.280104148725 - 11 -3372.342164165108 - 21 -1259.280104148725 - 72 - 1 - 10 -3372.342164165108 - 20 -1259.280104148725 - 11 -3372.342164165108 - 21 -1258.780104148725 - 72 - 1 - 10 -3372.342164165108 - 20 -1258.780104148725 - 11 -3372.572164165089 - 21 -1258.780104148725 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -854 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3372.3421641686 - 20 -1259.280104150704 - 10 -3372.572164165323 - 20 -1259.280104150704 - 10 -3372.572164165089 - 20 -1258.780104148725 - 10 -3372.342164165108 - 20 -1258.780104148725 - 10 -3372.342164165108 - 20 -1259.280104148725 - 0 -HATCH - 5 -855 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3372.342164165108 - 20 -1256.050104161259 - 11 -3372.342164165108 - 21 -1255.550104161259 - 72 - 1 - 10 -3372.342164165108 - 20 -1255.550104161259 - 11 -3372.572164165089 - 21 -1255.550104161259 - 72 - 1 - 10 -3372.572164165089 - 20 -1255.550104161259 - 11 -3372.572164165089 - 21 -1256.050104161259 - 72 - 1 - 10 -3372.572164165089 - 20 -1256.050104161259 - 11 -3372.342164165108 - 21 -1256.050104161259 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -856 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3372.572164165323 - 20 -1255.550104161433 - 10 -3372.3421641686 - 20 -1255.550104161433 - 10 -3372.3421641686 - 20 -1256.050104161433 - 10 -3372.572164165089 - 20 -1256.050104161259 - 10 -3372.572164165089 - 20 -1255.550104161259 - 0 -LWPOLYLINE - 5 -857 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3380.579634535358 - 20 -1243.823737554077 - 10 -3384.039634535323 - 20 -1243.823737554077 - 10 -3384.039634535323 - 20 -1245.238323131401 - 0 -LINE - 5 -858 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3384.041146070231 - 20 -1245.952369962644 - 11 -3384.039634535323 - 21 -1245.238323131401 - 0 -LINE - 5 -859 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3383.891146406299 - 20 -1245.952687490498 - 11 -3383.88963487139 - 21 -1245.238640659197 - 0 -LINE - 5 -85A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3384.039634535323 - 20 -1245.238323131401 - 11 -3383.809634535341 - 21 -1245.238323131401 - 0 -LINE - 5 -85B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3372.572164165089 - 20 -1257.100104148732 - 11 -3373.322164165089 - 21 -1257.100104148732 - 0 -LINE - 5 -85C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3372.572164165089 - 20 -1257.300104148744 - 11 -3373.322164165089 - 21 -1257.300104148744 - 0 -LINE - 5 -85D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3372.572164165089 - 20 -1257.500104148756 - 11 -3373.322164165089 - 21 -1257.500104148756 - 0 -LINE - 5 -85E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3372.572164165089 - 20 -1257.700104148709 - 11 -3373.322164165089 - 21 -1257.700104148709 - 0 -LINE - 5 -85F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3372.572164165089 - 20 -1257.900104148721 - 11 -3373.322164165089 - 21 -1257.900104148721 - 0 -LINE - 5 -860 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3372.572164165089 - 20 -1258.100104148732 - 11 -3373.322164165089 - 21 -1258.100104148732 - 0 -LINE - 5 -861 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3372.572164165089 - 20 -1258.300104148744 - 11 -3373.322164165089 - 21 -1258.300104148744 - 0 -LWPOLYLINE - 5 -862 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3373.322164165089 - 20 -1258.300104148744 - 10 -3373.322164165089 - 20 -1258.100104148732 - 0 -LWPOLYLINE - 5 -863 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3373.322164165089 - 20 -1257.900104148721 - 10 -3373.322164165089 - 20 -1257.100104148732 - 0 -LWPOLYLINE - 5 -864 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3373.422164165182 - 20 -1258.300104148744 - 10 -3373.422164165182 - 20 -1256.300104148744 - 0 -LINE - 5 -865 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1256.300104148744 - 11 -3374.172164165182 - 21 -1256.300104148744 - 0 -LINE - 5 -866 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1256.500104148756 - 11 -3374.172164165182 - 21 -1256.500104148756 - 0 -LINE - 5 -867 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1256.700104148709 - 11 -3374.172164165182 - 21 -1256.700104148709 - 0 -LINE - 5 -868 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1256.900104148721 - 11 -3374.172164165182 - 21 -1256.900104148721 - 0 -LINE - 5 -869 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1257.100104148732 - 11 -3374.172164165182 - 21 -1257.100104148732 - 0 -LINE - 5 -86A -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1257.300104148744 - 11 -3374.172164165182 - 21 -1257.300104148744 - 0 -LINE - 5 -86B -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1257.500104148756 - 11 -3374.172164165182 - 21 -1257.500104148756 - 0 -LINE - 5 -86C -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1257.700104148709 - 11 -3374.172164165182 - 21 -1257.700104148709 - 0 -LINE - 5 -86D -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1257.900104148721 - 11 -3374.172164165182 - 21 -1257.900104148721 - 0 -LINE - 5 -86E -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1258.100104148732 - 11 -3374.172164165182 - 21 -1258.100104148732 - 0 -LINE - 5 -86F -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1258.300104148744 - 11 -3374.172164165182 - 21 -1258.300104148744 - 0 -LWPOLYLINE - 5 -870 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3374.172164165182 - 20 -1259.050104148744 - 10 -3374.172164165182 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -871 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3373.322164165089 - 20 -1257.100104148732 - 10 -3373.322164165089 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -872 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3373.322164165089 - 20 -1258.100104148732 - 10 -3373.322164165089 - 20 -1258.300104148744 - 10 -3373.422164165182 - 20 -1258.300104148744 - 10 -3373.422164165182 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -873 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3373.292164165294 - 20 -1257.100104148732 - 10 -3373.292164165294 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -874 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3373.292164165294 - 20 -1258.100104148732 - 10 -3373.292164165294 - 20 -1258.330104148714 - 10 -3373.45216416521 - 20 -1258.330104148714 - 10 -3373.45216416521 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -875 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3373.262164165267 - 20 -1257.100104148732 - 10 -3373.262164165267 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -876 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3373.262164165267 - 20 -1258.100104148732 - 10 -3373.262164165267 - 20 -1258.360104148741 - 10 -3373.482164165238 - 20 -1258.360104148741 - 10 -3373.482164165238 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -877 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3374.172164166812 - 20 -1255.998735667846 - 10 -3374.172164166812 - 20 -1259.280104150704 - 0 -LWPOLYLINE - 5 -878 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3372.342164165108 - 20 -1256.050104161259 - 10 -3372.3421641686 - 20 -1259.280104150704 - 10 -3374.172164166812 - 20 -1259.280104150704 - 0 -LWPOLYLINE - 5 -879 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3372.392164165154 - 20 -1256.050104161259 - 10 -3372.392164165154 - 20 -1259.230104148737 - 10 -3374.172164165182 - 20 -1259.230104148737 - 0 -LWPOLYLINE - 5 -87A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3372.442164165201 - 20 -1256.050104161259 - 10 -3372.442164165201 - 20 -1259.180104148749 - 10 -3374.172164165182 - 20 -1259.180104148749 - 0 -LWPOLYLINE - 5 -87B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3372.572164165089 - 20 -1256.050104161259 - 10 -3372.572164165089 - 20 -1259.050104148744 - 10 -3374.172164165182 - 20 -1259.050104148744 - 0 -LWPOLYLINE - 5 -87C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3374.402164165164 - 20 -1259.280104148725 - 10 -3374.402164165164 - 20 -1255.550104161259 - 0 -LWPOLYLINE - 5 -87D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3383.539634535555 - 20 -1249.590104149363 - 10 -3384.029634537641 - 20 -1249.590104149363 - 0 -LWPOLYLINE - 5 -87E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3374.402164165164 - 20 -1259.280104148725 - 10 -3384.039634535323 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -87F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3384.039634535555 - 20 -1249.590104149363 - 10 -3384.039634535555 - 20 -1259.280104150704 - 0 -LWPOLYLINE - 5 -880 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3377.575810121838 - 20 -1244.522369963757 - 10 -3377.575810121838 - 20 -1245.052802683494 - 0 -LINE - 5 -881 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3373.050299706403 - 20 -1240.067414091609 - 11 -3373.050299706403 - 21 -1260.721494616649 - 0 -CIRCLE - 5 -882 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3373.050299706403 - 20 -1241.147899744741 - 40 -0.3105759447062155 - 0 -HATCH - 5 -883 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3373.360875650542 - 20 -1241.147899743053 - 11 -3373.050299705937 - 21 -1241.458475687774 - 72 - 1 - 10 -3373.050299705937 - 20 -1241.458475687774 - 11 -3373.050299705937 - 21 -1240.837323798332 - 72 - 1 - 10 -3373.050299705937 - 20 -1240.837323798332 - 11 -3373.360875650542 - 21 -1241.147899743053 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -884 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3373.050299706403 - 20 -1240.837323801301 - 10 -3373.360875649844 - 20 -1241.147899741016 - 10 -3373.050299706403 - 20 -1241.458475688181 - 10 -3373.050299706403 - 20 -1240.837323801301 - 0 -MTEXT - 5 -885 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3373.336266792613 - 20 -1241.193436495552 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -CIRCLE - 5 -886 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3373.050299706403 - 20 -1260.305064083717 - 40 -0.3105759447062155 - 0 -HATCH - 5 -887 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3373.360875650542 - 20 -1260.305064084648 - 11 -3373.050299705937 - 21 -1260.615640029369 - 72 - 1 - 10 -3373.050299705937 - 20 -1260.615640029369 - 11 -3373.050299705937 - 21 -1259.994488139986 - 72 - 1 - 10 -3373.050299705937 - 20 -1259.994488139986 - 11 -3373.360875650542 - 21 -1260.305064084648 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -888 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3373.050299706403 - 20 -1259.994488125376 - 10 -3373.360875657294 - 20 -1260.305064087442 - 10 -3373.050299706403 - 20 -1260.615640027157 - 10 -3373.050299706403 - 20 -1259.994488125376 - 0 -MTEXT - 5 -889 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3373.336266792613 - 20 -1260.350600837148 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -88A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3374.402164170984 - 20 -1259.280104150704 - 10 -3384.039634535555 - 20 -1259.280104150704 - 10 -3384.039634535555 - 20 -1249.590104149363 - 0 -LWPOLYLINE - 5 -88B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3374.402164165164 - 20 -1259.180104148749 - 10 -3383.939634535229 - 20 -1259.180104148749 - 10 -3383.939634535229 - 20 -1249.590104148723 - 0 -LINE - 5 -88C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3383.539634535555 - 20 -1249.360104148916 - 11 -3383.539634535555 - 21 -1249.590104149363 - 0 -LWPOLYLINE - 5 -88D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3377.575810118579 - 20 -1242.945116815506 - 10 -3380.809634538833 - 20 -1243.423737553589 - 10 -3380.809634538833 - 20 -1243.823737552098 - 10 -3384.039634535555 - 20 -1243.823737552098 - 10 -3384.039634535555 - 20 -1245.238323131285 - 0 -LWPOLYLINE - 5 -88E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3377.575810118579 - 20 -1243.04620614968 - 10 -3380.709634535248 - 20 -1243.510026432865 - 10 -3380.709634535248 - 20 -1243.923737554054 - 10 -3383.939634535229 - 20 -1243.923737554054 - 10 -3383.939634535229 - 20 -1245.238323131343 - 0 -LINE - 5 -88F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3375.389031755272 - 20 -1249.590104149363 - 11 -3384.039634535555 - 21 -1249.590104149363 - 0 -HATCH - 5 -890 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3374.402164165164 - 20 -1258.780104148725 - 11 -3374.402164165164 - 21 -1259.280104148725 - 72 - 1 - 10 -3374.402164165164 - 20 -1259.280104148725 - 11 -3374.172164165182 - 21 -1259.280104148725 - 72 - 1 - 10 -3374.172164165182 - 20 -1259.280104148725 - 11 -3374.172164165182 - 21 -1258.780104148725 - 72 - 1 - 10 -3374.172164165182 - 20 -1258.780104148725 - 11 -3374.402164165164 - 21 -1258.780104148725 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -891 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3374.172164166812 - 20 -1259.280104150704 - 10 -3374.402164170984 - 20 -1259.280104150704 - 10 -3374.402164165164 - 20 -1258.780104148725 - 10 -3374.172164166812 - 20 -1258.780104150704 - 10 -3374.172164166812 - 20 -1259.280104150704 - 0 -HATCH - 5 -892 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3374.172164165182 - 20 -1256.050104161259 - 11 -3374.172164165182 - 21 -1255.550104161259 - 72 - 1 - 10 -3374.172164165182 - 20 -1255.550104161259 - 11 -3374.402164165164 - 21 -1255.550104161259 - 72 - 1 - 10 -3374.402164165164 - 20 -1255.550104161259 - 11 -3374.402164165164 - 21 -1256.050104161259 - 72 - 1 - 10 -3374.402164165164 - 20 -1256.050104161259 - 11 -3374.172164165182 - 21 -1256.050104161259 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -893 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3374.402164170984 - 20 -1255.550104161433 - 10 -3374.172164166812 - 20 -1255.550104161433 - 10 -3374.172164165182 - 20 -1256.050104161259 - 10 -3374.402164165164 - 20 -1256.050104161259 - 10 -3374.402164165164 - 20 -1255.550104161259 - 0 -HATCH - 5 -894 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANGLE - 70 - 0 - 71 - 0 - 91 - 2 - 92 - 0 - 93 - 6 - 72 - 1 - 10 -3383.939634535229 - 20 -1259.180104148749 - 11 -3374.402164165164 - 21 -1259.180104148749 - 72 - 1 - 10 -3374.402164165164 - 20 -1259.180104148749 - 11 -3374.402164165164 - 21 -1258.780104148725 - 72 - 1 - 10 -3374.402164165164 - 20 -1258.780104148725 - 11 -3374.402164165164 - 21 -1249.590104148723 - 72 - 1 - 10 -3374.402164165164 - 20 -1249.590104148723 - 11 -3375.389031757601 - 21 -1249.590104148723 - 72 - 1 - 10 -3375.389031757601 - 20 -1249.590104148723 - 11 -3383.939634535229 - 21 -1249.590104148723 - 72 - 1 - 10 -3383.939634535229 - 20 -1249.590104148723 - 11 -3383.939634535229 - 21 -1259.180104148749 - 97 - 0 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3375.839075485012 - 20 -1252.165106727509 - 11 -3381.418439672329 - 21 -1252.121452173392 - 72 - 1 - 10 -3381.418439672096 - 20 -1252.121452173392 - 11 -3381.426624931628 - 21 -1253.167586872005 - 72 - 1 - 10 -3381.426624931628 - 20 -1253.167586871947 - 11 -3375.847260744311 - 21 -1253.211241426062 - 72 - 1 - 10 -3375.847260744544 - 20 -1253.211241426062 - 11 -3375.839075485012 - 21 -1252.16510672745 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -1.5 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -MTEXT - 5 -895 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3375.995849914151 - 20 -1252.932892533427 - 30 -0 - 40 -0.4900000000000003 - 41 -4.831944444444448 - 71 - 1 - 72 - 5 - 1 -OPEN TERRACE - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -896 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3372.3421641686 - 20 -1255.550104161433 - 10 -3372.572164165323 - 20 -1255.550104161433 - 0 -LWPOLYLINE - 5 -897 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3373.472164171282 - 20 -1255.550104161433 - 10 -3374.402164170984 - 20 -1255.550104161433 - 0 -LWPOLYLINE - 5 -898 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3372.342164165108 - 20 -1255.650104161235 - 10 -3372.572164165089 - 20 -1255.650104161235 - 0 -LWPOLYLINE - 5 -899 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 7 - 70 - 0 - 43 -0 - 10 -3383.889951367848 - 20 -1245.388153112131 - 10 -3377.425810118672 - 20 -1245.388323131366 - 10 -3377.425810118672 - 20 -1242.822369963012 - 10 -3375.912164165173 - 20 -1242.822369963012 - 10 -3375.912164165173 - 20 -1242.402369962656 - 10 -3372.492164165247 - 20 -1242.402369962656 - 10 -3372.492164165247 - 20 -1255.550104161259 - 0 -LWPOLYLINE - 5 -89A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3374.402164170984 - 20 -1255.550104161433 - 10 -3374.402164170984 - 20 -1249.590104149363 - 10 -3384.039634535555 - 20 -1249.590104149363 - 10 -3384.039634535555 - 20 -1245.238323131285 - 0 -LWPOLYLINE - 5 -89B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3374.252164165259 - 20 -1255.550104161259 - 10 -3374.252164165259 - 20 -1249.440104148758 - 10 -3383.8895990575 - 20 -1249.440104148758 - 10 -3383.891145760948 - 20 -1245.95238262658 - 0 -LWPOLYLINE - 5 -89C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3372.3421641686 - 20 -1255.550104161433 - 10 -3372.3421641686 - 20 -1241.721707736782 - 10 -3372.572164165323 - 20 -1241.721707736782 - 10 -3372.572164165323 - 20 -1242.252369960479 - 0 -LWPOLYLINE - 5 -89D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 0 - 43 -0 - 10 -3372.3421641686 - 20 -1255.550104161433 - 10 -3372.3421641686 - 20 -1242.154635777406 - 10 -3372.572164165323 - 20 -1242.154635777406 - 10 -3372.572164165323 - 20 -1242.252369960479 - 10 -3376.002164172474 - 20 -1242.252369960479 - 10 -3376.04216417158 - 20 -1242.252369960479 - 10 -3376.062164167408 - 20 -1242.252369960479 - 10 -3376.062164167408 - 20 -1242.722369963012 - 0 -LINE - 5 -89E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3373.472164171282 - 20 -1255.550104161433 - 11 -3372.572164165323 - 21 -1255.550104161433 - 0 -MTEXT - 5 -89F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3283.061831855216 - 20 -1235.06983288523 - 30 -0 - 40 -0.4900000000000003 - 41 -8.234722118341177 - 71 - 1 - 72 - 5 - 1 -BASEMENT FLOOR PLAN - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8A0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3300.488247429719 - 20 -1235.06983288523 - 30 -0 - 40 -0.4900000000000003 - 41 -7.363611111111177 - 71 - 1 - 72 - 5 - 1 -GROUND FLOOR PLAN - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8A1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3316.827640795847 - 20 -1235.06983288523 - 30 -0 - 40 -0.4900000000000003 - 41 -6.60138878500784 - 71 - 1 - 72 - 5 - 1 -FIRST FLOOR PLAN - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8A2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3352.992303687148 - 20 -1235.06983288523 - 30 -0 - 40 -0.4900000000000003 - 41 -6.887222118341204 - 71 - 1 - 72 - 5 - 1 -SECOND FLOOR PLAN - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8A3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3375.789232264273 - 20 -1235.06983288523 - 30 -0 - 40 -0.4900000000000003 - 41 -7.322777777777783 - 71 - 1 - 72 - 5 - 1 -TERRACE FLOOR PLAN - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LINE - 5 -8A4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3402.461395606632 - 20 -1238.89051844005 - 11 -3402.461395606632 - 21 -1236.271455681242 - 0 -LINE - 5 -8A5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3392.995761112077 - 20 -1237.146906384849 - 11 -3402.461395606632 - 21 -1237.146906384849 - 0 -LINE - 5 -8A6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3392.995761112077 - 20 -1236.271455681242 - 11 -3402.461395606632 - 21 -1236.271455681242 - 0 -TEXT - 5 -8A7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbText - 10 -3393.180831600912 - 20 -1236.521544189367 - 30 -0 - 40 -0.4857686858836294 - 1 -RS - 50 -0 - 41 -1 - 51 -0 - 7 -sree - 71 - 0 -210 -0 -220 -0 -230 -1 -100 -AcDbText - 0 -MTEXT - 5 -8A8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3395.870399698615 - 20 -1237.882763578906 - 30 -0 - 40 -0.4857686858836294 - 41 -1.997048835998051 - 71 - 1 - 72 - 5 - 1 -GLASS - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LINE - 5 -8A9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3392.995761112077 - 20 -1238.89051844005 - 11 -3402.461395606632 - 21 -1238.89051844005 - 0 -LINE - 5 -8AA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3392.995761112077 - 20 -1238.89051844005 - 11 -3392.995761112077 - 21 -1236.271455681242 - 0 -MTEXT - 5 -8AB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - -1 -100 -AcDbMText - 10 -3394.543313582195 - 20 -1238.775882851973 - 30 -0 - 40 -0.492075 - 41 -4.538024895679042 - 71 - 1 - 72 - 5 - 1 -SPECIFICATION - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8AC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3393.152249841718 - 20 -1237.882763578906 - 30 -0 - 40 -0.4857686858836294 - 41 -0.269871492157602 - 71 - 1 - 72 - 5 - 1 -G - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -TEXT - 5 -8AD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbText - 10 -3395.910303766374 - 20 -1236.521544189367 - 30 -0 - 40 -0.4857686858836294 - 1 -ROLLING SHUTTER - 50 -0 - 41 -1 - 51 -0 - 7 -sree - 71 - 0 -210 -0 -220 -0 -230 -1 -100 -AcDbText - 0 -LINE - 5 -8AE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3395.251624739031 - 20 -1238.022357088455 - 11 -3395.251624739031 - 21 -1236.271455681242 - 0 -LINE - 5 -8AF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3392.995761112077 - 20 -1238.022357088455 - 11 -3402.461395606632 - 21 -1238.022357088455 - 0 -LINE - 5 -8B0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3403.873485771474 - 20 -1251.320821476576 - 11 -3403.873485771474 - 21 -1240.039741707151 - 0 -LINE - 5 -8B1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1249.920970887702 - 11 -3403.873485771474 - 21 -1249.920970887702 - 0 -LINE - 5 -8B2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1248.509366719052 - 11 -3403.873485771474 - 21 -1248.509366719052 - 0 -LINE - 5 -8B3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1252.720672065392 - 11 -3403.873485771474 - 21 -1252.720672065392 - 0 -LINE - 5 -8B4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1251.320821476576 - 11 -3389.961759146769 - 21 -1240.039741707151 - 0 -MTEXT - 5 -8B5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - -1 -100 -AcDbMText - 10 -3394.439554924146 - 20 -1251.090687079879 - 30 -0 - 40 -0.7934371614720003 - 41 -9.058407425261716 - 71 - 1 - 72 - 5 - 1 -JOINERY DETAILS - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8B6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3390.218430102339 - 20 -1249.772946545738 - 30 -0 - 40 -0.7832686628247535 - 41 -0.4351492571249116 - 71 - 1 - 72 - 5 - 1 -D - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8B7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3392.294592137914 - 20 -1249.623572336684 - 30 -0 - 40 -0.7832686628247535 - 41 -12.05363409024947 - 71 - 1 - 72 - 5 - 1 -SINGLE SHUTTER DOOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LINE - 5 -8B8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3391.983519680565 - 20 -1249.920970887702 - 11 -3391.983519680565 - 21 -1240.039741707151 - 0 -LINE - 5 -8B9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3400.016167183407 - 20 -1249.920970887702 - 11 -3400.016167183407 - 21 -1240.039741707151 - 0 -LINE - 5 -8BA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1247.097762550402 - 11 -3403.873485771474 - 21 -1247.097762550402 - 0 -LINE - 5 -8BB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1245.686158381752 - 11 -3403.873485771474 - 21 -1245.686158381752 - 0 -LINE - 5 -8BC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1244.274554213101 - 11 -3403.873485771474 - 21 -1244.274554213101 - 0 -LINE - 5 -8BD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1242.862950044451 - 11 -3403.873485771474 - 21 -1242.862950044451 - 0 -MTEXT - 5 -8BE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3390.218430102339 - 20 -1248.361342377087 - 30 -0 - 40 -0.7832686628247535 - 41 -0.8702985142497746 - 71 - 1 - 72 - 5 - 1 -D1 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8BF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3390.218430102339 - 20 -1246.949738208437 - 30 -0 - 40 -0.7832686628247535 - 41 -1.04435821709972 - 71 - 1 - 72 - 5 - 1 -D2 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8C0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3390.218430102339 - 20 -1244.126529871137 - 30 -0 - 40 -0.7832686628247535 - 41 -1.827626879924473 - 71 - 1 - 72 - 5 - 1 -GW1 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8C1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3390.218430102339 - 20 -1242.714925702486 - 30 -0 - 40 -0.7832686628247535 - 41 -0.5221791085498356 - 71 - 1 - 72 - 5 - 1 -V - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8C2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3392.294592137914 - 20 -1248.211968168034 - 30 -0 - 40 -0.7832686628247535 - 41 -12.05363409024947 - 71 - 1 - 72 - 5 - 1 -SINGLE SHUTTER DOOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8C3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3392.294592137914 - 20 -1246.800363999384 - 30 -0 - 40 -0.7832686628247535 - 41 -12.05363409024947 - 71 - 1 - 72 - 5 - 1 -SINGLE SHUTTER DOOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8C4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3392.294592137914 - 20 -1242.565551493433 - 30 -0 - 40 -0.7832686628247535 - 41 -6.266149302598027 - 71 - 1 - 72 - 5 - 1 -VENTILATOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8C5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3392.294592137914 - 20 -1243.977155662083 - 30 -0 - 40 -0.7832686628247535 - 41 -8.072018387557025 - 71 - 1 - 72 - 5 - 1 -GLASS WINDOW - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8C6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3390.218430102339 - 20 -1245.538134039787 - 30 -0 - 40 -0.7832686628247535 - 41 -1.827626879924473 - 71 - 1 - 72 - 5 - 1 -D2A - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8C7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3392.294592137914 - 20 -1245.388759830734 - 30 -0 - 40 -0.7832686628247535 - 41 -12.48878351342902 - 71 - 1 - 72 - 5 - 1 -DOUBLE SHUTTER DOOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LINE - 5 -8C8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1241.451345875801 - 11 -3403.873485771474 - 21 -1241.451345875801 - 0 -LINE - 5 -8C9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1240.039741707151 - 11 -3403.873485771474 - 21 -1240.039741707151 - 0 -MTEXT - 5 -8CA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3390.218430102339 - 20 -1241.303321533836 - 30 -0 - 40 -0.7832686628247535 - 41 -0.9573283656746986 - 71 - 1 - 72 - 5 - 1 -V1 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8CB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3392.294592137914 - 20 -1241.153947324783 - 30 -0 - 40 -0.7832686628247535 - 41 -6.266149302598027 - 71 - 1 - 72 - 5 - 1 -VENTILATOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8CC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3400.637843515724 - 20 -1246.800363999384 - 30 -0 - 40 -0.7832686628247535 - 41 -3.394164205573932 - 71 - 1 - 72 - 5 - 1 -80X210 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8CD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3400.637843515724 - 20 -1245.388759830734 - 30 -0 - 40 -0.7832686628247535 - 41 -3.829313462698794 - 71 - 1 - 72 - 5 - 1 -120X210 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8CE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3400.637843515724 - 20 -1243.977155662083 - 30 -0 - 40 -0.7832686628247535 - 41 -4.090403016973712 - 71 - 1 - 72 - 5 - 1 -420X120 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8CF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3400.637843515724 - 20 -1242.565551493433 - 30 -0 - 40 -0.7832686628247535 - 41 -3.39416420557398 - 71 - 1 - 72 - 5 - 1 -100X60 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8D0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3400.637843515724 - 20 -1241.153947324783 - 30 -0 - 40 -0.7832686628247535 - 41 -2.959014948449117 - 71 - 1 - 72 - 5 - 1 -80X60 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LINE - 5 -8D1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3403.873485771474 - 20 -1262.590147666109 - 11 -3403.873485771474 - 21 -1252.720672065392 - 0 -LINE - 5 -8D2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.29848577152 - 20 -1261.190297077293 - 11 -3403.873485771474 - 21 -1261.190297077293 - 0 -LINE - 5 -8D3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbLine - 10 -3389.29848577152 - 20 -1259.778692908643 - 11 -3403.873485771474 - 21 -1259.778692908643 - 0 -LINE - 5 -8D4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.29848577152 - 20 -1262.590147666109 - 11 -3403.873485771474 - 21 -1262.590147666109 - 0 -LINE - 5 -8D5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.29848577152 - 20 -1262.590147666109 - 11 -3389.29848577152 - 21 -1252.720672065392 - 0 -MTEXT - 5 -8D6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - -1 -100 -AcDbMText - 10 -3393.863485771464 - 20 -1262.360013269412 - 30 -0 - 40 -0.7934371614720003 - 41 -7.647852471533669 - 71 - 1 - 72 - 5 - 1 -AREA DETAILS - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8D7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3389.515393301612 - 20 -1261.042272735329 - 30 -0 - 40 -0.7832686628247535 - 41 -3.046044799874041 - 71 - 1 - 72 - 5 - 1 -FLOOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8D8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3396.669611776946 - 20 -1260.892898526275 - 30 -0 - 40 -0.7832686628247535 - 41 -1.653567003014777 - 71 - 1 - 72 - 5 - 1 -(M)² - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8D9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3400.525844009593 - 20 -1260.716449584055 - 30 -0 - 40 -0.6 - 41 -2.783333206132044 - 71 - 1 - 72 - 5 - 1 -SQ .FT. - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LINE - 5 -8DA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3395.685985771474 - 20 -1261.190297077293 - 11 -3395.685985771474 - 21 -1252.720672065392 - 0 -LINE - 5 -8DB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3399.890535136917 - 20 -1261.190297077293 - 11 -3399.890535136917 - 21 -1252.720672065392 - 0 -LINE - 5 -8DC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.29848577152 - 20 -1258.367088739993 - 11 -3403.873485771474 - 21 -1258.367088739993 - 0 -LINE - 5 -8DD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.29848577152 - 20 -1256.955484571343 - 11 -3403.873485771474 - 21 -1256.955484571343 - 0 -LINE - 5 -8DE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.29848577152 - 20 -1255.543880402692 - 11 -3403.873485771474 - 21 -1255.543880402692 - 0 -LINE - 5 -8DF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.29848577152 - 20 -1254.132276234042 - 11 -3403.873485771474 - 21 -1254.132276234042 - 0 -LINE - 5 -8E0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.29848577152 - 20 -1252.720672065392 - 11 -3403.873485771474 - 21 -1252.720672065392 - 0 -MTEXT - 5 -8E1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3389.484574149598 - 20 -1253.981169540319 - 30 -0 - 40 -0.7832686628247535 - 41 -12.01011949664632 - 71 - 1 - 72 - 5 - 1 -TOTAL AREA \H1.305x; - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8E2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3389.515393301612 - 20 -1259.630668566679 - 30 -0 - 40 -0.7832686628247535 - 41 -9.203406622136212 - 71 - 1 - 72 - 5 - 1 -BASEMENT FLOOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8E3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3389.515393301612 - 20 -1258.219064398028 - 30 -0 - 40 -0.7832686628247535 - 41 -7.810929165391389 - 71 - 1 - 72 - 5 - 1 -GROUND FLOOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8E4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3389.515393301612 - 20 -1256.807460229378 - 30 -0 - 40 -0.7832686628247535 - 41 -6.592511079387035 - 71 - 1 - 72 - 5 - 1 -FIRST FLOOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8E5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3389.515393301612 - 20 -1255.395856060728 - 30 -0 - 40 -0.7832686628247535 - 41 -7.636869296486754 - 71 - 1 - 72 - 5 - 1 -SECOND FLOOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8E6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3400.637843515724 - 20 -1249.623572336684 - 30 -0 - 40 -0.7832686628247535 - 41 -3.829313462698794 - 71 - 1 - 72 - 5 - 1 -100X210 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8E7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3400.637843515724 - 20 -1248.211968168034 - 30 -0 - 40 -0.7832686628247535 - 41 -3.39416420557398 - 71 - 1 - 72 - 5 - 1 -90X210 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LINE - 5 -8E8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1251.320821476576 - 11 -3403.873485771474 - 21 -1251.320821476576 - 0 -LWPOLYLINE - 5 -8E9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3204.645300902426 - 20 -1297.791080966592 - 10 -3512.634034834802 - 20 -1297.791080966592 - 10 -3512.634034834802 - 20 -1170.354015154764 - 10 -3204.645300902426 - 20 -1170.354015154764 - 0 -LWPOLYLINE - 5 -8EA -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 13 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3672.274958058858 - 20 -1102.020476120804 - 10 -3698.046045772997 - 20 -1107.029812435309 - 10 -3711.150773975219 - 20 -1109.577085239756 - 10 -3734.342027092429 - 20 -1114.084958081897 - 0 -LWPOLYLINE - 5 -8EB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3672.503926400916 - 20 -1100.842523023958 - 10 -3698.275014115051 - 20 -1105.851859338477 - 10 -3711.379742317273 - 20 -1108.399132142923 - 10 -3734.570995434026 - 20 -1112.907004984988 - 0 -LWPOLYLINE - 5 -8EC -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 5 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3672.732894742511 - 20 -1099.664569927048 - 10 -3698.503982456645 - 20 -1104.673906241568 - 10 -3711.608710659329 - 20 -1107.221179046091 - 10 -3734.79996377608 - 20 -1111.729051888156 - 0 -LWPOLYLINE - 5 -8ED -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3672.732894742511 - 20 -1099.664569927048 - 10 -3698.535822601603 - 20 -1104.680095269986 - 10 -3711.583342462243 - 20 -1107.216248022903 - 10 -3734.79996377608 - 20 -1111.729051888156 - 0 -LWPOLYLINE - 5 -8EE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3674.266571524048 - 20 -1090.284878494705 - 10 -3700.474522549609 - 20 -1095.379131490835 - 10 -3713.295592722377 - 20 -1097.871267372712 - 10 -3736.793186846377 - 20 -1102.438686212563 - 0 -DIMENSION - 5 -8EF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D9 - 10 -3711.230201477702 - 20 -1109.216627534068 - 30 -0 - 11 -3704.648994248611 - 21 -1108.067294854499 - 31 -0 - 70 - 33 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3698.036505425412 - 23 -1107.07889381435 - 33 -0 - 14 -3711.150255169002 - 24 -1109.627920209303 - 34 -0 - 0 -DIMENSION - 5 -8F0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D10 - 10 -3713.217161291157 - 20 -1133.099397961581 - 30 -0 - 11 -3713.464588759269 - 21 -1121.35131122986 - 31 -0 - 70 - 33 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3711.150773975219 - 23 -1109.577085239756 - 33 -0 - 14 -3710.910952621411 - 24 -1133.075861498266 - 34 -0 - 0 -DIMENSION - 5 -8F1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D11 - 10 -3710.921396379202 - 20 -1133.764259275178 - 30 -0 - 11 -3706.148880246726 - 21 -1133.964201744781 - 31 -0 - 70 - 33 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3701.362051457872 - 23 -1133.220728919789 - 33 -0 - 14 -3710.910952621411 - 24 -1133.075861498266 - 34 -0 - 0 -DIMENSION - 5 -8F2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D12 - 10 -3698.046045772998 - 20 -1107.029812435309 - 30 -0 - 11 -3699.577535147486 - 21 -1120.141288420921 - 31 -0 - 70 - 33 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3701.362051457872 - 23 -1133.220728919789 - 33 -0 - 14 -3698.046045772997 - 24 -1107.029812435309 - 34 -0 - 0 -DIMENSION - 5 -8F3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D13 - 10 -3710.910953230301 - 20 -1133.06586149814 - 30 -0 - 11 -3704.36416309136 - 21 -1120.099311220429 - 31 -0 - 70 - 33 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3698.046046381595 - 23 -1107.019812435327 - 33 -0 - 14 -3710.910953230009 - 24 -1133.065861498284 - 34 -0 - 0 -MTEXT - 5 -8F4 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3712.323898692514 - 20 -1133.91149679323 - 30 -0 - 40 -0.68 - 41 -5.213333333333333 - 71 - 5 - 72 - 1 - 1 -\W0.8;\C7;A - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8F5 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3701.773331511015 - 20 -1134.48415198065 - 30 -0 - 40 -0.68 - 41 -5.137777777777778 - 71 - 5 - 72 - 1 - 1 -\W0.8;\C7;B - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8F6 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3697.726812683696 - 20 -1106.181686485057 - 30 -0 - 40 -0.68 - 41 -5.062222222222222 - 71 - 5 - 72 - 1 - 1 -\W0.8;\C7;C - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -DIMENSION - 5 -8F7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D14 - 10 -3707.769716797048 - 20 -1107.700478565418 - 30 -0 - 11 -3707.792422192403 - 21 -1108.337826670716 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3707.650442678567 - 23 -1108.947633137341 - 33 -0 - 14 -3707.882337505863 - 24 -1107.719313071169 - 34 -0 - 50 -99.49419111659763 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -8F8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D15 - 10 -3707.883887015795 - 20 -1106.500234520827 - 30 -0 - 11 -3707.910477738811 - 21 -1107.114350354412 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3707.764369543838 - 23 -1107.699584299413 - 33 -0 - 14 -3707.997366203883 - 24 -1106.519212597268 - 34 -0 - 50 -99.49419111659763 -100 -AcDbRotatedDimension - 0 -LWPOLYLINE - 5 -8F9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3902.410987750695 - 20 -1301.511978900197 - 10 -3908.645015031192 - 20 -1317.660538005052 - 10 -3919.79417200274 - 20 -1304.419114605728 - 10 -3902.410987750695 - 20 -1301.511978900197 - 0 -LWPOLYLINE - 5 -8FA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3907.964280239541 - 20 -1302.440702581859 - 10 -3913.795947310683 - 20 -1303.415981179812 - 10 -3916.251905305514 - 20 -1288.730608818905 - 10 -3910.420238234371 - 20 -1287.755330220952 - 0 -MTEXT - 5 -8FB -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3915.837736036229 - 20 -1277.818292432038 - 30 -0 - 40 -17 - 41 -128.4444444444445 - 71 - 5 - 72 - 1 - 1 -\W0.8;\C7;N - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LINE - 5 -8FC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3663.245809017876 - 20 -1160.995536376621 - 11 -3672.669210381117 - 21 -1099.652191078797 - 0 -LINE - 5 -8FD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3674.057129834356 - 20 -1091.466627146058 - 11 -3679.859521877605 - 21 -1056.771291184111 - 0 -LINE - 5 -8FE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3650.917277298526 - 20 -1157.080735647538 - 11 -3668.042934631451 - 21 -1054.678066143961 - 0 -LINE - 5 -8FF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3621.930008000513 - 20 -1254.46536760834 - 11 -3663.99190321545 - 21 -1052.405737075454 - 0 -LINE - 5 -900 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3662.37448808464 - 20 -1052.133037315658 - 11 -3619.794049828615 - 21 -1252.689056581804 - 0 -LINE - 5 -901 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3616.773343549434 - 20 -1252.154285308986 - 11 -3658.815639063021 - 21 -1051.533007518213 - 0 -LINE - 5 -902 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3657.136829126123 - 20 -1051.249956458653 - 11 -3614.717015578778 - 21 -1251.400859422596 - 0 -TEXT - 5 -903 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbText - 10 -3650.532340746764 - 20 -1103.953173562304 - 30 -0 - 40 -1.657499999999999 - 1 -RAILWAY TRACK - 50 -102.8084861050996 - 41 -1 - 51 -0 - 7 -title1 - 71 - 0 -210 -0 -220 -0 -230 -1 -100 -AcDbText - 0 -LWPOLYLINE - 5 -904 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3734.045064322938 - 20 -1115.532748664855 - 10 -3735.513223449404 - 20 -1108.374992958203 - 10 -3737.183521288859 - 20 -1108.654330875672 - 10 -3734.523073473556 - 20 -1107.097492335758 - 10 -3735.812381152563 - 20 -1106.916501354847 - 10 -3737.466308103384 - 20 -1099.179022704292 - 0 -LWPOLYLINE - 5 -905 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3734.289965661031 - 20 -1115.582981468166 - 10 -3735.709697833853 - 20 -1108.661322993018 - 10 -3738.48306120235 - 20 -1109.125135810973 - 10 -3735.270236731759 - 20 -1107.245057980108 - 10 -3736.020305085218 - 20 -1107.139764566295 - 10 -3737.710785243486 - 20 -1099.231280984955 - 0 -ARC - 5 -906 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbCircle - 10 -3818.945751805638 - 20 -1144.502502475059 - 40 -168.498605913861 -100 -AcDbArc - 50 -165.8980910274046 - 51 -175.7189518822834 - 0 -LWPOLYLINE - 5 -907 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3715.527812990941 - 20 -1117.558899958314 - 10 -3721.394442062317 - 20 -1118.540025544813 - 10 -3719.024216116146 - 20 -1132.712764114562 - 10 -3713.157587044769 - 20 -1131.731638528063 - 0 -LWPOLYLINE - 5 -908 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3724.30195298597 - 20 -1119.259218588376 - 10 -3730.168582057345 - 20 -1120.240344174874 - 10 -3727.798356111176 - 20 -1134.413082744609 - 10 -3721.9317270398 - 20 -1133.43195715811 - 0 -LWPOLYLINE - 5 -909 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3700.343149125929 - 20 -1092.025307210313 - 10 -3709.849342566172 - 20 -1093.615107673399 - 10 -3710.836675324316 - 20 -1087.711362891115 - 10 -3701.330481884074 - 20 -1086.121562428029 - 0 -LWPOLYLINE - 5 -90A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3687.924933325221 - 20 -1090.476234095497 - 10 -3697.431126765005 - 20 -1092.066034558506 - 10 -3698.418459523152 - 20 -1086.162289776208 - 10 -3688.912266083369 - 20 -1084.572489313198 - 0 -LWPOLYLINE - 5 -90B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3715.520024993609 - 20 -1095.503398078453 - 10 -3725.026218433391 - 20 -1097.093198541463 - 10 -3726.013551191539 - 20 -1091.189453759165 - 10 -3716.507357751758 - 20 -1089.599653296155 - 0 -LWPOLYLINE - 5 -90C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3730.111157028579 - 20 -1097.400565809753 - 10 -3739.617350468821 - 20 -1098.990366272839 - 10 -3740.604683226966 - 20 -1093.086621490555 - 10 -3731.098489786725 - 20 -1091.496821027469 - 0 -MTEXT - 5 -90D -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - -1 -100 -AcDbMText - 10 -3683.251112048439 - 20 -1114.12964576591 - 30 -0 - 40 -0.4875 - 41 -6.093750000000153 - 71 - 7 - 72 - 5 - 1 -\pi3.93533;VENKAY\P\pi3.99469; TOWER - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -90E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3710.831567484591 - 20 -1121.009345265736 - 30 -0 - 40 -0.6375000000000001 - 41 -10.07604166666675 - 71 - 7 - 72 - 5 - 1 -\pi3.91991;EXT BUILDING \P\pi4.81919;LEE FOOT - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -90F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3719.626778997 - 20 -1122.835452260726 - 30 -0 - 40 -0.6375000000000001 - 41 -8.252083333333415 - 71 - 7 - 72 - 5 - 1 -\pi6.1779;EXT \P\pi4.90986;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -910 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3727.780280034512 - 20 -1093.017050375303 - 30 -0 - 40 -0.75 - 41 -13.10416666666667 - 71 - 7 - 72 - 5 - 1 -\pi6.5171;HOTEL \P\pi4.40907;ARYA BHAVAN - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -911 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - -1 -100 -AcDbMText - 10 -3698.069957093073 - 20 -1087.615453141374 - 30 -0 - 40 -0.75 - 41 -7.791666666666852 - 71 - 7 - 72 - 5 - 1 -\pi6.84836;HDFC \P\pi6.7642;BANK - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -912 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3685.768474956669 - 20 -1086.011476629512 - 30 -0 - 40 -0.75 - 41 -10.60416666666676 - 71 - 7 - 72 - 5 - 1 -\pi5.48521;CITY MALL - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -913 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3712.784151652958 - 20 -1091.392069092912 - 30 -0 - 40 -0.75 - 41 -9.791666666666806 - 71 - 7 - 72 - 5 - 1 -\pi5.92186;FATHIMA \P\pi5.67322;COMPLEX - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -914 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3677.098770806683 - 20 -1044.045040395329 - 30 -0 - 40 -2.486249999999999 - 41 -57.94343697290994 - 71 - 7 - 72 - 5 - 1 -\pi13.76172; TO RAILWAY STATION - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -99.98548591323963 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -915 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3666.374137997014 - 20 -1109.409636466498 - 30 -0 - 40 -2.486249999999999 - 41 -48.62000000000014 - 71 - 7 - 72 - 5 - 1 -\pi17.87438; TO MANANCHIRA - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -99.9854859132396 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -916 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3653.116060949333 - 20 -1050.572046072458 - 10 -3667.774039996447 - 20 -1053.043413681799 - 10 -3668.698795209776 - 20 -1058.665144988168 - 10 -3672.173384880478 - 20 -1050.022186411365 - 10 -3673.141891634795 - 20 -1055.150948849436 - 10 -3683.410463330815 - 20 -1057.627804650409 - 0 -LWPOLYLINE - 5 -917 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3612.769074736673 - 20 -1250.687145911562 - 10 -3617.020982355601 - 20 -1252.245018640379 - 10 -3617.670522814061 - 20 -1255.217242955204 - 10 -3619.401430566409 - 20 -1251.721848409485 - 10 -3620.300663649409 - 20 -1253.937087626049 - 10 -3623.7785897269 - 20 -1255.064730610394 - 0 -INSERT - 5 -918 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 5 -370 - -1 -100 -AcDbBlockReference - 2 -WELL10 - 10 -3698.046045772997 - 20 -1107.029812435309 - 30 -0 - 41 -1 - 42 -1 - 43 -0 - 50 -9.494191116597097 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -919 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 5 -370 - -1 -100 -AcDbBlockReference - 2 -WELL10 - 10 -3711.399878877084 - 20 -1109.619960983812 - 30 -0 - 41 -1 - 42 -1 - 43 -0 - 50 -9.494191116597097 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -91A -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 5 -370 - -1 -100 -AcDbBlockReference - 2 -WELL10 - 10 -3686.53303422432 - 20 -1104.467213811765 - 30 -0 - 41 -1 - 42 -1 - 43 -0 - 50 -9.494191116597097 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -91B -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 5 -370 - -1 -100 -AcDbBlockReference - 2 -WELL10 - 10 -3715.05218281703 - 20 -1097.489077892062 - 30 -0 - 41 -1 - 42 -1 - 43 -0 - 50 -9.494191116597097 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -MTEXT - 5 -91C -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - -1 -100 -AcDbMText - 10 -3679.544715149916 - 20 -1103.254248217038 - 30 -0 - 40 -0.4875 - 41 -9.005208333333394 - 71 - 7 - 72 - 5 - 1 -\pi2.64974;PYRA 021025008 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -91D -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - -1 -100 -AcDbMText - 10 -3689.581212828417 - 20 -1105.779364616607 - 30 -0 - 40 -0.4875 - 41 -8.951041666666756 - 71 - 7 - 72 - 5 - 1 -\pi2.64958;PYRA 021025007 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -91E -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - -1 -100 -AcDbMText - 10 -3707.31302465503 - 20 -1108.040408999108 - 30 -0 - 40 -0.4875 - 41 -8.788541666666788 - 71 - 7 - 72 - 5 - 1 -\pi2.65157;PYRA 021025002 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -91F -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - -1 -100 -AcDbMText - 10 -3706.732580925164 - 20 -1095.66068097573 - 30 -0 - 40 -0.4875 - 41 -8.951041666666757 - 71 - 7 - 72 - 5 - 1 -\pi2.64908;PYRA 021025003 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -920 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3711.273699996203 - 20 -1118.425295046578 - 30 -0 - 40 -0.6375000000000001 - 41 -7.897916666666905 - 71 - 7 - 72 - 5 - 1 -\pi5.42756;61/4736 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -921 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3720.192266075204 - 20 -1120.260175708412 - 30 -0 - 40 -0.6375000000000001 - 41 -6.977083333333533 - 71 - 7 - 72 - 5 - 1 -\pi5.67521;7/1166 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -ARC - 5 -922 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbCircle - 10 -3696.917764457168 - 20 -1163.455614783708 - 40 -33.76170269503877 -100 -AcDbArc - 50 -145.9430062472594 - 51 -184.17861443943 - 0 -LWPOLYLINE - 5 -923 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3734.720354382054 - 20 -1114.158496639986 - 10 -3738.686929918392 - 20 -1115.844574412406 - 10 -3747.207562453121 - 20 -1127.42575798961 - 10 -3737.984766603963 - 20 -1184.359010964738 - 10 -3668.946837908695 - 20 -1182.362751978026 - 0 -LWPOLYLINE - 5 -924 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3655.525037135472 - 20 -1185.556737477315 - 10 -3661.933689675147 - 20 -1239.604914529362 - 10 -3658.703168783311 - 20 -1265.862401451442 - 0 -LWPOLYLINE - 5 -925 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 9 - 70 - 0 - 43 -0 - 10 -3742.066222901291 - 20 -1254.329491668528 - 10 -3819.194022095526 - 20 -1161.743556749656 - 10 -3819.194022095526 - 20 -1161.743556749656 - 10 -3776.239488607737 - 20 -1132.452708329507 - 10 -3758.509204227333 - 20 -1131.852486874133 - 10 -3748.595375559345 - 20 -1195.614530581304 - 10 -3673.269371679385 - 20 -1193.436449416088 - 10 -3673.114885321725 - 20 -1244.148526421946 - 10 -3669.288083184822 - 20 -1268.660956136343 - 0 -LWPOLYLINE - 5 -926 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3755.835392925514 - 20 -1264.313243891627 - 10 -3810.771350095322 - 20 -1197.481873112261 - 0 -LWPOLYLINE - 5 -927 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3827.40763642424 - 20 -1177.910735801946 - 10 -3832.929692907018 - 20 -1171.458535321766 - 10 -3894.524955233329 - 20 -1130.214806844929 - 0 -LINE - 5 -928 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3828.253191330998 - 20 -1186.90839669684 - 11 -3864.34204721124 - 21 -1201.334960825953 - 0 -LINE - 5 -929 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3817.569851347105 - 20 -1195.732796192468 - 11 -3857.877077122608 - 21 -1211.845658829175 - 0 -LINE - 5 -92A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3864.34204721124 - 20 -1201.334960825953 - 11 -3933.839036880242 - 21 -1206.669498169772 - 0 -LINE - 5 -92B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3857.877077122608 - 20 -1211.845658829175 - 11 -3929.506972431524 - 21 -1217.343916426788 - 0 -LWPOLYLINE - 5 -92C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3674.038517828119 - 20 -1091.463009378749 - 10 -3736.519598054338 - 20 -1103.607966068941 - 0 -LWPOLYLINE - 5 -92D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3737.002057368151 - 20 -1102.479286077857 - 10 -3737.002057368151 - 20 -1102.479286077857 - 10 -3744.458612101624 - 20 -1106.673476415998 - 10 -3754.921112308807 - 20 -1123.52750767798 - 10 -3775.957144170349 - 20 -1123.614223775269 - 10 -3786.290409368626 - 20 -1089.978103280969 - 0 -LWPOLYLINE - 5 -92E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3886.141628373118 - 20 -1118.068975034996 - 10 -3831.721186576351 - 20 -1154.344822695818 - 10 -3827.417943474372 - 20 -1152.525487771688 - 10 -3784.152615093123 - 20 -1122.975655641954 - 10 -3793.044350720756 - 20 -1091.894007347209 - 0 -LWPOLYLINE - 5 -92F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3674.272604962561 - 20 -1243.869123794117 - 10 -3726.24568563805 - 20 -1244.707679792736 - 10 -3727.000240668569 - 20 -1197.940917009035 - 10 -3675.036768652261 - 20 -1196.506823406191 - 0 -MTEXT - 5 -930 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3756.865414159386 - 20 -1168.433523472095 - 30 -0 - 40 -1.95 - 41 -31.09166666666691 - 71 - 7 - 72 - 5 - 1 -\pi12.13862;MANANCHIRA \P\pi15.70874;SQUARE - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -931 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3776.474118560167 - 20 -1133.461032298888 - 30 -0 - 40 -1.949999999999999 - 41 -30.76666583985863 - 71 - 7 - 72 - 5 - 1 -\pi13.32312;S M STREET - 7 -standard -210 -0 -220 -0 -230 -1 - 50 --74.25125576525804 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -932 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3736.326966023149 - 20 -1104.442964096322 - 30 -0 - 40 -1.325999999999998 - 41 -25.52550000000013 - 71 - 7 - 72 - 5 - 1 -\pi8.1862;VAIKOM MUHAMMED \P\pi10.31088;BASHEER ROAD - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -53.22066029237218 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -933 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3820.722082429027 - 20 -1189.452004851772 - 30 -0 - 40 -1.949999999999999 - 41 -31.03749958659616 - 71 - 7 - 72 - 5 - 1 -\pi13.07039;TO STADIUM - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -21.68440044093668 - 73 - 1 - 44 -1 - 0 -ARC - 5 -934 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbCircle - 10 -3834.105824746369 - 20 -1181.819834705566 - 40 -7.755435580095657 -100 -AcDbArc - 50 -138.9947282420557 - 51 -210.268066171013 - 0 -ARC - 5 -935 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbCircle - 10 -3815.511662832165 - 20 -1201.843414851171 - 40 -6.441553476017277 -100 -AcDbArc - 50 -218.4994950327385 - 51 -293.6827425064117 - 0 -MTEXT - 5 -936 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3842.007876331594 - 20 -1175.051070345304 - 30 -0 - 40 -1.2675 - 41 -29.68062473128743 - 71 - 7 - 72 - 5 - 1 -\pi2.91262;OFFICE OF THE DISTRICT \P\pi7.83001;POLICE CHIEF - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -CIRCLE - 5 -937 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbCircle - 10 -3831.925447103324 - 20 -1141.843907025075 - 40 -9.277483467537976 - 0 -MTEXT - 5 -938 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3826.388260593409 - 20 -1139.603241054131 - 30 -0 - 40 -1.95 - 41 -25.89166666666679 - 71 - 7 - 72 - 5 - 1 -\pi0.48612;PATTALA \P\pi2.99013;PALLI - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -939 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3803.912872544535 - 20 -1126.360022534351 - 30 -0 - 40 -1.949999999999999 - 41 -21.34166666666666 - 71 - 7 - 72 - 5 - 1 -\pi4.71733;LIC \P\pi1.87014;OFFICE - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -34.78643956249795 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -93A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3793.943289383552 - 20 -1127.962435105929 - 10 -3817.668917594136 - 20 -1144.166456730874 - 10 -3824.533853563994 - 20 -1133.668178075407 - 10 -3800.492363226739 - 20 -1117.947192073396 - 0 -MTEXT - 5 -93B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3700.088415629728 - 20 -1159.660879081114 - 30 -0 - 40 -1.95 - 41 -27.84166625326284 - 71 - 7 - 72 - 5 - 1 -\pi13.86915;COMTREST\P\pi15.0184;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -93C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3679.516723670458 - 20 -1212.583629483431 - 30 -0 - 40 -1.95 - 41 -31.09166666666691 - 71 - 7 - 72 - 5 - 1 -\pi12.13862;MANANCHIRA \P\pi17.65076;POND - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -93D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3652.272450410219 - 20 -1264.786938479666 - 10 -3660.97369299198 - 20 -1266.242120259089 - 10 -3661.759734923516 - 20 -1271.020591869534 - 10 -3664.713136143153 - 20 -1263.674077079174 - 10 -3665.536366884463 - 20 -1268.033525151566 - 10 -3672.163893108268 - 20 -1269.141901950961 - 0 -LWPOLYLINE - 5 -93E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3781.614055392398 - 20 -1089.196037382174 - 10 -3788.267946778666 - 20 -1090.308823448827 - 10 -3788.869037667352 - 20 -1093.962948797974 - 10 -3791.12752095285 - 20 -1088.345025722963 - 10 -3791.757050343477 - 20 -1091.678721307767 - 10 -3796.825158631947 - 20 -1092.526303566073 - 0 -LWPOLYLINE - 5 -93F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3884.914400272256 - 20 -1116.482956246178 - 10 -3889.9505181377 - 20 -1124.024111787149 - 10 -3888.159683642405 - 20 -1127.265539579696 - 10 -3893.41192072271 - 20 -1124.252930730671 - 10 -3891.84184139424 - 20 -1127.26036891067 - 10 -3895.296435145634 - 20 -1131.064300997811 - 0 -LWPOLYLINE - 5 -940 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3931.931295981563 - 20 -1216.668312205154 - 10 -3932.638934645709 - 20 -1210.977787222031 - 10 -3935.72075832738 - 20 -1210.336939251194 - 10 -3930.869154464132 - 20 -1208.619355164397 - 10 -3933.67783825718 - 20 -1207.965787985093 - 10 -3934.216829528292 - 20 -1203.631452607232 - 0 -LWPOLYLINE - 5 -941 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3740.087966829236 - 20 -1252.976053281332 - 10 -3747.526265395394 - 20 -1257.719563682483 - 10 -3746.380090707456 - 20 -1262.424660539552 - 10 -3751.972359748435 - 20 -1256.819271587518 - 10 -3751.024350711658 - 20 -1261.153296877611 - 10 -3756.689922995719 - 20 -1264.766314131312 - 0 -LWPOLYLINE - 5 -942 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3774.717837631432 - 20 -1213.704493785373 - 10 -3782.15613619713 - 20 -1218.448004186448 - 10 -3781.009961509651 - 20 -1223.153101043594 - 10 -3786.602230550632 - 20 -1217.547712091545 - 10 -3785.654221513854 - 20 -1221.881737381653 - 10 -3791.319793797454 - 20 -1225.494754635277 - 0 -LWPOLYLINE - 5 -943 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3775.27882247923 - 20 -1212.526682639575 - 10 -3782.777444825555 - 20 -1217.308662386455 - 10 -3781.698986123465 - 20 -1221.735782183009 - 10 -3787.280224343788 - 20 -1216.141449930808 - 10 -3786.274038221407 - 20 -1220.741444162287 - 10 -3791.880778645253 - 20 -1224.316943489479 - 0 -LWPOLYLINE - 5 -944 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3733.704584040967 - 20 -1180.601809104001 - 10 -3706.058145653754 - 20 -1178.541714453807 - 10 -3708.528557137903 - 20 -1145.388830495251 - 10 -3736.174995524656 - 20 -1147.448925145369 - 0 -LWPOLYLINE - 5 -945 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3810.32292119011 - 20 -1237.036034494414 - 10 -3818.976684631721 - 20 -1226.316203024725 - 10 -3809.467087609203 - 20 -1218.639421604025 - 10 -3800.813324167589 - 20 -1229.359253073728 - 0 -LWPOLYLINE - 5 -946 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3822.486698941423 - 20 -1222.093152370142 - 10 -3831.140462383036 - 20 -1211.373320900453 - 10 -3821.630865360518 - 20 -1203.696539479753 - 10 -3812.977101918903 - 20 -1214.416370949456 - 0 -MTEXT - 5 -947 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3788.880713943821 - 20 -1222.566900670318 - 30 -0 - 40 -1.95 - 41 -23.07500000000049 - 71 - 7 - 72 - 5 - 1 -\pi17.87955;DTPC \P\pi16.55206;OFFICE - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -948 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3800.763668755769 - 20 -1207.948432676019 - 30 -0 - 40 -1.95 - 41 -24.32083333333345 - 71 - 7 - 72 - 5 - 1 -\pi19.61805;DD\P\pi16.11444; OFFICE - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -949 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3839.201383212925 - 20 -1179.70943669257 - 10 -3861.520849822987 - 20 -1197.290328442092 - 10 -3875.379086879443 - 20 -1179.696883031727 - 10 -3853.059620269839 - 20 -1162.115991282282 - 0 -MTEXT - 5 -94A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3854.042164330117 - 20 -1147.729192656701 - 30 -0 - 40 -1.949999999999999 - 41 -32.77083333333368 - 71 - 7 - 72 - 5 - 1 -\pi12.54033;TO PALAYAM - 7 -standard -210 -0 -220 -0 -230 -1 - 50 --33.43452738982237 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -94B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3753.7439683156 - 20 -1121.612594720044 - 10 -3760.220504389338 - 20 -1122.695720170199 - 10 -3761.161025697201 - 20 -1117.071883912244 - 10 -3754.684489623463 - 20 -1115.988758462089 - 0 -LWPOLYLINE - 5 -94C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3763.581401153643 - 20 -1121.905275219842 - 10 -3770.057937227381 - 20 -1122.988400669997 - 10 -3770.998458535244 - 20 -1117.364564412042 - 10 -3764.521922461506 - 20 -1116.281438961887 - 0 -MTEXT - 5 -94D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3762.778898677414 - 20 -1118.272107638218 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -94E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3752.728789273267 - 20 -1117.935263517171 - 30 -0 - 40 -0.414375 - 41 -5.58255208333336 - 71 - 7 - 72 - 5 - 1 -\pi3.24384;DISTRICT\P\pi3.18448; LIBRARY - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -94F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3764.306415485752 - 20 -1143.712097525969 - 10 -3775.96418041839 - 20 -1145.661723336233 - 10 -3777.657118772541 - 20 -1135.538818071929 - 10 -3765.999353839904 - 20 -1133.589192261665 - 0 -MTEXT - 5 -950 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3762.723633438748 - 20 -1137.791174678556 - 30 -0 - 40 -0.745875 - 41 -14.10946827561897 - 71 - 7 - 72 - 5 - 1 -\pi3.56669;DISTRICT SPORTS \P\pi3.81523;COUNCIL OFFICE - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -951 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3748.337464807924 - 20 -1112.244153926456 - 10 -3754.814000881662 - 20 -1113.327279376612 - 10 -3755.754522189525 - 20 -1107.703443118657 - 10 -3749.277986115787 - 20 -1106.620317668502 - 0 -MTEXT - 5 -952 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3748.100495253421 - 20 -1108.726756509799 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -953 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3741.845017537538 - 20 -1104.480484601143 - 10 -3748.321553611276 - 20 -1105.563610051298 - 10 -3749.26207491914 - 20 -1099.939773793344 - 10 -3742.785538845402 - 20 -1098.856648343189 - 0 -MTEXT - 5 -954 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3740.732738448468 - 20 -1102.710442323006 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -955 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3731.576376615175 - 20 -1125.983411118625 - 10 -3738.052912688914 - 20 -1127.066536568781 - 10 -3738.993433996775 - 20 -1121.44270031084 - 10 -3732.516897923036 - 20 -1120.359574860685 - 0 -MTEXT - 5 -956 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3731.33940706067 - 20 -1122.466013701968 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -957 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3737.545788317888 - 20 -1132.311689039405 - 10 -3744.022324391627 - 20 -1133.39481448956 - 10 -3744.96284569949 - 20 -1127.770978231606 - 10 -3738.486309625751 - 20 -1126.68785278145 - 0 -MTEXT - 5 -958 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - -1 -100 -AcDbMText - 10 -3737.308818763382 - 20 -1128.794291622748 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -959 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3770.699442659021 - 20 -1114.214100435279 - 10 -3777.175978732759 - 20 -1115.297225885435 - 10 -3778.116500040622 - 20 -1109.67338962748 - 10 -3771.639963966884 - 20 -1108.590264177325 - 0 -MTEXT - 5 -95A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3770.462473104514 - 20 -1110.696703018622 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -95B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3773.259528943675 - 20 -1103.848141244923 - 10 -3779.736065017413 - 20 -1104.931266695079 - 10 -3780.676586325277 - 20 -1099.307430437123 - 10 -3774.200050251539 - 20 -1098.224304986968 - 0 -MTEXT - 5 -95C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3773.022559389171 - 20 -1100.330743828266 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -95D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3775.766091565003 - 20 -1096.827935949267 - 10 -3782.242627638742 - 20 -1097.911061399423 - 10 -3783.183148946603 - 20 -1092.287225141482 - 10 -3776.706612872864 - 20 -1091.204099691327 - 0 -MTEXT - 5 -95E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3775.529122010957 - 20 -1093.310538532687 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -95F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3791.254872115195 - 20 -1106.387796302059 - 10 -3797.731408188933 - 20 -1107.470921752215 - 10 -3798.671929496794 - 20 -1101.847085494274 - 10 -3792.195393423056 - 20 -1100.763960044119 - 0 -MTEXT - 5 -960 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3791.017902561149 - 20 -1102.870398885479 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -961 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3787.955071879999 - 20 -1113.571129457761 - 10 -3794.431607953738 - 20 -1114.654254907916 - 10 -3795.3721292616 - 20 -1109.030418649975 - 10 -3788.895593187862 - 20 -1107.94729319982 - 0 -MTEXT - 5 -962 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3787.718102325494 - 20 -1110.053732041103 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -963 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3793.519755518178 - 20 -1099.875339826408 - 10 -3799.996291591916 - 20 -1100.958465276563 - 10 -3800.93681289978 - 20 -1095.334629018609 - 10 -3794.460276826041 - 20 -1094.251503568453 - 0 -MTEXT - 5 -964 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3793.282785963672 - 20 -1096.357942409751 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -965 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3845.580330387984 - 20 -1144.77593660757 - 10 -3853.926442873503 - 20 -1139.545311696947 - 10 -3849.384481292614 - 20 -1132.298047191109 - 10 -3841.038368807096 - 20 -1137.528672101732 - 0 -MTEXT - 5 -966 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3841.813517766818 - 20 -1141.064513595265 - 30 -0 - 40 -0.6215625000000001 - 41 -7.76953125000004 - 71 - 7 - 72 - 5 - 1 -\pi6.02345;EXT \P\pi4.78711;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 --32.07594501240991 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -967 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3855.873158925529 - 20 -1136.519144882714 - 10 -3864.219271411048 - 20 -1131.288519972091 - 10 -3859.677309830161 - 20 -1124.041255466252 - 10 -3851.331197344642 - 20 -1129.271880376875 - 0 -MTEXT - 5 -968 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3852.106346303904 - 20 -1132.807721870331 - 30 -0 - 40 -0.6215625000000001 - 41 -7.76953125000004 - 71 - 7 - 72 - 5 - 1 -\pi6.02345;EXT \P\pi4.78711;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 --32.07594501240991 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -969 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3866.838061140937 - 20 -1129.756339161086 - 10 -3875.184173625997 - 20 -1124.525714250386 - 10 -3870.64221204511 - 20 -1117.278449744548 - 10 -3862.296099560049 - 20 -1122.509074655247 - 0 -MTEXT - 5 -96A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3863.071248519311 - 20 -1126.044916148703 - 30 -0 - 40 -0.6215625000000001 - 41 -7.76953125000004 - 71 - 7 - 72 - 5 - 1 -\pi6.02345;EXT \P\pi4.78711;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 --32.07594501240991 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -96B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3875.525977642258 - 20 -1155.304222796561 - 10 -3883.872090127777 - 20 -1150.073597885938 - 10 -3879.330128546889 - 20 -1142.8263333801 - 10 -3870.98401606137 - 20 -1148.056958290723 - 0 -MTEXT - 5 -96C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3871.759165021093 - 20 -1151.592799784256 - 30 -0 - 40 -0.6215625000000001 - 41 -7.76953125000004 - 71 - 7 - 72 - 5 - 1 -\pi6.02345;EXT \P\pi4.78711;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 --32.07594501240991 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -96D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3886.246650705176 - 20 -1149.158494117503 - 10 -3894.592763190694 - 20 -1143.92786920688 - 10 -3890.050801609806 - 20 -1136.680604701041 - 10 -3881.704689124286 - 20 -1141.911229611664 - 0 -MTEXT - 5 -96E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3882.479838083551 - 20 -1145.44707110512 - 30 -0 - 40 -0.6215625000000001 - 41 -7.76953125000004 - 71 - 7 - 72 - 5 - 1 -\pi6.02345;EXT \P\pi4.78711;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 --32.07594501240991 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -96F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3862.886892206504 - 20 -1164.730942536645 - 10 -3871.233004692022 - 20 -1159.500317626022 - 10 -3866.691043111135 - 20 -1152.253053120183 - 10 -3858.344930625616 - 20 -1157.483678030806 - 0 -MTEXT - 5 -970 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3859.120079585338 - 20 -1161.019519524339 - 30 -0 - 40 -0.6215625000000001 - 41 -6.388281118227492 - 71 - 7 - 72 - 5 - 1 -\pi5.69041;BSNL - 7 -standard -210 -0 -220 -0 -230 -1 - 50 --32.07594501240991 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -971 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3700.13337714789 - 20 -1140.795822503287 - 10 -3706.609913221628 - 20 -1141.878947953442 - 10 -3707.550434529491 - 20 -1136.255111695487 - 10 -3701.073898455753 - 20 -1135.171986245332 - 0 -MTEXT - 5 -972 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3699.896407593384 - 20 -1137.27842508663 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -973 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3643.462846576567 - 20 -1207.930555156724 - 10 -3653.177650687173 - 20 -1209.555243331957 - 10 -3654.588432648967 - 20 -1201.119488945032 - 10 -3644.87362853836 - 20 -1199.494800769799 - 0 -MTEXT - 5 -974 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - -1 -100 -AcDbMText - 10 -3642.143861537395 - 20 -1202.996452783886 - 30 -0 - 40 -0.6215625000000001 - 41 -9.54789062500004 - 71 - 7 - 72 - 5 - 1 -\pi4.24547;TOWN HALL - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -975 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3640.537600089015 - 20 -1183.410616360269 - 10 -3650.252404199621 - 20 -1185.035304535502 - 10 -3651.663186161414 - 20 -1176.599550148577 - 10 -3641.948382050808 - 20 -1174.974861973343 - 0 -MTEXT - 5 -976 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3637.675691773953 - 20 -1178.825241802199 - 30 -0 - 40 -0.6215625000000001 - 41 -8.045781250000001 - 71 - 7 - 72 - 5 - 1 -\pi5.19456;CROWN \P\pi4.78881;THEATER - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -977 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3601.604909471302 - 20 -1272.231191164763 - 10 -3933.002492243144 - 20 -1327.653588559505 - 10 -3972.194044686567 - 20 -1093.308155027997 - 10 -3640.796461914725 - 20 -1037.885757633255 - 0 -LWPOLYLINE - 5 -978 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3681.434333434648 - 20 -1118.611448071486 - 10 -3693.771926796752 - 20 -1120.674767292133 - 10 -3695.126580710478 - 20 -1112.574629917997 - 10 -3682.788987348374 - 20 -1110.51131069735 - 0 -DIMENSION - 5 -979 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D16 - 10 -3696.042765219429 - 20 -1106.640418470341 - 30 -0 - 11 -3695.673365105243 - 21 -1109.622356924703 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3695.126580710478 - 23 -1112.574629917997 - 33 -0 - 14 -3696.042765217587 - 24 -1106.640418470033 - 34 -0 - 50 -99.49419111659763 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -97A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D17 - 10 -3683.833249802431 - 20 -1104.267155469601 - 30 -0 - 11 -3683.436895234262 - 21 -1107.4102677691 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3682.788987348374 - 23 -1110.51131069735 - 33 -0 - 14 -3683.833249800589 - 24 -1104.267155469293 - 34 -0 - 50 -99.49419111659763 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -97B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D18 - 10 -3716.871847356197 - 20 -1110.680308081277 - 30 -0 - 11 -3716.419807051285 - 21 -1114.156392598132 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3715.527812990941 - 23 -1117.558899958314 - 33 -0 - 14 -3716.546538312589 - 24 -1110.625903921355 - 34 -0 - 50 -99.49419111659763 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -97C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D19 - 10 -3725.456101013639 - 20 -1112.358003846994 - 30 -0 - 11 -3725.004803658664 - 21 -1115.829645903309 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3724.30195298597 - 23 -1119.259218588376 - 33 -0 - 14 -3725.466256737647 - 24 -1112.359702273902 - 34 -0 - 50 -99.49419111659763 -100 -AcDbRotatedDimension - 0 -LINE - 5 -97D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3673.226113949546 - 20 -1096.143998159776 - 11 -3736.982881325131 - 21 -1108.536920556109 - 0 -LINE - 5 -97E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3736.78093467197 - 20 -1102.385368843452 - 11 -3674.250989227 - 21 -1090.230913822521 - 0 -LINE - 5 -97F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3734.331979996244 - 20 -1114.133940960085 - 11 -3672.201238672091 - 21 -1102.057082497029 - 0 -LWPOLYLINE - 5 -980 -100 -AcDbEntity - 8 -BLK_1_FLR_0_BLT_UP_AREA - 6 -CONTINUOUS - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 11 - 70 - 1 - 43 -0 - 10 -3298.794476717245 - 20 -1259.280104148725 - 10 -3310.491947087228 - 20 -1259.280104148725 - 10 -3310.491947087228 - 20 -1243.823737554077 - 10 -3307.261947087351 - 20 -1243.823737554077 - 10 -3307.261947087351 - 20 -1243.423737554054 - 10 -3304.028122670717 - 20 -1243.423737553589 - 10 -3304.028122670717 - 20 -1242.722369962663 - 10 -3302.454476717161 - 20 -1242.722369962663 - 10 -3302.454476717161 - 20 -1242.252369962749 - 10 -3299.024476717227 - 20 -1242.252369962632 - 10 -3298.794476717245 - 20 -1242.252369962632 - 0 -LWPOLYLINE - 5 -981 -100 -AcDbEntity - 8 -BLK_1_BSMNT_FRONT_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 11 - 70 - 1 - 43 -0 - 10 -3699.232777040069 - 20 -1113.775649733053 - 10 -3702.961422993541 - 20 -1113.775649733043 - 10 -3702.961422993541 - 20 -1114.343383919057 - 10 -3704.46743068438 - 20 -1114.343702468373 - 10 -3704.467387999287 - 20 -1115.045070058 - 10 -3707.700247410171 - 20 -1115.045252870157 - 10 -3707.700247523737 - 20 -1115.444751510496 - 10 -3710.930247410173 - 20 -1115.444751510471 - 10 -3710.931485144911 - 20 -1110.563998297215 - 10 -3710.931545268003 - 20 -1109.58540778369 - 10 -3699.234207207088 - 20 -1107.312053327475 - 0 -LWPOLYLINE - 5 -982 -100 -AcDbEntity - 8 -BLK_1_LVL_0_REAR_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 1 - 43 -0 - 10 -3699.232777040192 - 20 -1130.901118105156 - 10 -3699.221250807438 - 20 -1132.969197142546 - 10 -3701.361437638996 - 20 -1133.220526157112 - 10 -3710.910075275855 - 20 -1133.07507759163 - 10 -3710.930245187186 - 20 -1130.901118105119 - 0 -LWPOLYLINE - 5 -983 -100 -AcDbEntity - 8 -BLK_1_BSMNT_SIDE_YARD_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3699.232777040069 - 20 -1130.901118105119 - 10 -3698.034300625808 - 20 -1130.90104516612 - 10 -3698.034300625808 - 20 -1113.775636794068 - 10 -3699.232777040069 - 20 -1113.775649733053 - 0 -MTEXT - 5 -984 -100 -AcDbEntity - 8 -BLK_1_LVL_0_FRONT_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3888.995942445637 - 20 -1107.198799397313 - 30 -0 - 40 -2.221171874999997 - 41 -23.93929687499997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=10.00 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -985 -100 -AcDbEntity - 8 -BLK_1_LVL_0_SIDE_YARD1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3889.412447205002 - 20 -1101.628360942278 - 30 -0 - 40 -2.221171874999997 - 41 -22.21171874999997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=10.0 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -986 -100 -AcDbEntity - 8 -BLK_1_LVL_0_SIDE_YARD2 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3889.558151292881 - 20 -1095.242230762686 - 30 -0 - 40 -2.221171874999997 - 41 -22.21171874999997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=10.0 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -987 -100 -AcDbEntity - 8 -BLK_1_LVL_0_REAR_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3889.025549273135 - 20 -1087.676971439328 - 30 -0 - 40 -2.221171874999997 - 41 -22.21171874999997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=10.0 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -988 -100 -AcDbEntity - 8 -BLK_1_DA_RAMP_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3823.217341994691 - 20 -1103.369298739781 - 30 -0 - 40 -2.221171874999997 - 41 -17.27578077910676 - 71 - 1 - 72 - 5 - 1 -SLOPE=1IN12 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -989 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -2951.195419034542 - 20 -1748.019487073325 - 10 -4256.185188137926 - 20 -1748.019487073325 - 10 -4256.185188137926 - 20 -754.7699488946961 - 10 -2951.195419034542 - 20 -754.7699488946961 - 0 -LWPOLYLINE - 5 -98A -100 -AcDbEntity - 8 -NOTIFIED_ROAD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3674.250989227 - 20 -1090.230913822521 - 10 -3672.296920324905 - 20 -1102.075680919548 - 10 -3734.331979996244 - 20 -1114.133940960085 - 10 -3736.78093467197 - 20 -1102.385368843452 - 0 -DIMENSION - 5 -98B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D20 - 10 -3692.548620250619 - 20 -1093.777223632806 - 30 -0 - 11 -3691.55878290749 - 21 -1099.695944551971 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3690.101075426844 - 23 -1105.536419623736 - 33 -0 - 14 -3692.167267226776 - 24 -1093.713446767995 - 34 -0 - 50 -99.49419111659763 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -98C -100 -AcDbEntity - 8 -BLK_1_MAX_HEIGHT_CAL - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D21 - 10 -3704.73684012501 - 20 -1096.17879616658 - 30 -0 - 11 -3703.281287270659 - 21 -1104.882257586579 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3702.961422993541 - 23 -1113.775649733043 - 33 -0 - 14 -3705.551110057835 - 24 -1096.31497335721 - 34 -0 - 50 -99.49419111659759 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -98D -100 -AcDbEntity - 8 -SHORTEST_DIST_TO_ROAD - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D22 - 10 -3704.067053513214 - 20 -1108.245004310187 - 30 -0 - 11 -3703.593239288494 - 21 -1111.078170974501 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3702.893813337845 - 23 -1113.87360669755 - 33 -0 - 14 -3703.84242825261 - 24 -1108.20743834379 - 34 -0 - 50 -99.49419111659759 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -98E -100 -AcDbEntity - 8 -DIST_CL_ROAD - 6 -ByLayer - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D23 - 10 -3704.822047500537 - 20 -1102.285557223309 - 30 -0 - 11 -3703.862084519889 - 21 -1108.025644738318 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3702.961422993541 - 23 -1113.775649732927 - 33 -0 - 14 -3704.82204750054 - 24 -1102.28555722331 - 34 -0 - 50 -99.49419111659759 -100 -AcDbRotatedDimension - 0 -LWPOLYLINE - 5 -98F -100 -AcDbEntity - 8 -BLK_1_FLR_1_BLT_UP_AREA - 6 -ByLayer - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 11 - 70 - 1 - 43 -0 - 10 -3315.64798602229 - 20 -1259.280104148725 - 10 -3327.345456392271 - 20 -1259.280104148725 - 10 -3327.345456392271 - 20 -1243.823737554077 - 10 -3324.115456392291 - 20 -1243.823737554077 - 10 -3324.115456392291 - 20 -1243.423737552314 - 10 -3321.200256110796 - 20 -1242.992274638342 - 10 -3320.811973281315 - 20 -1242.934807011575 - 10 -3319.307986022206 - 20 -1242.722369962663 - 10 -3319.307986022206 - 20 -1242.252369962749 - 10 -3315.877986022272 - 20 -1242.252369962632 - 10 -3315.64798602229 - 20 -1242.252369962632 - 0 -LWPOLYLINE - 5 -990 -100 -AcDbEntity - 8 -BLK_1_FLR_2_BLT_UP_AREA - 6 -CONTINUOUS - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 13 - 70 - 1 - 43 -0 - 10 -3351.858675254043 - 20 -1259.280104130454 - 10 -3353.918675253634 - 20 -1259.280104148725 - 10 -3353.918675253634 - 20 -1249.590104149363 - 10 -3363.546145619592 - 20 -1249.590104148723 - 10 -3363.55765715451 - 20 -1245.952369962644 - 10 -3357.092321204488 - 20 -1245.95236997268 - 10 -3357.09232120309 - 20 -1244.522369962651 - 10 -3357.09232120309 - 20 -1243.423737554054 - 10 -3357.09232120309 - 20 -1242.722369944391 - 10 -3355.51867525396 - 20 -1242.722369944391 - 10 -3355.51867525396 - 20 -1242.252369944477 - 10 -3352.088675254026 - 20 -1242.252369944361 - 10 -3351.858675254043 - 20 -1242.252369944361 - 0 -LWPOLYLINE - 5 -991 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_BLT_UP_AREA - 6 -CONTINUOUS - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 11 - 70 - 1 - 43 -0 - 10 -3281.373068378307 - 20 -1259.280104148725 - 10 -3293.070538748289 - 20 -1259.280104148725 - 10 -3293.070538748289 - 20 -1243.823737554077 - 10 -3289.840538748288 - 20 -1243.823737554077 - 10 -3289.840538748288 - 20 -1243.423737554054 - 10 -3286.606714331778 - 20 -1243.423737553589 - 10 -3286.606714331778 - 20 -1242.722369962663 - 10 -3285.101714331658 - 20 -1242.722369962663 - 10 -3285.101714331658 - 20 -1242.154635776649 - 10 -3281.605333485642 - 20 -1242.154635776649 - 10 -3281.373068378185 - 20 -1242.154635776659 - 0 -INSERT - 5 -992 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -*U4 - 10 --5492.970809899844 - 20 --1659.111589305452 - 30 -0 - 41 -0.01 - 42 -0.01 - 43 -0 - 50 -0 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -993 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -*U4 - 10 --5476.117300597593 - 20 --1659.111589307198 - 30 -0 - 41 -0.01 - 42 -0.01 - 43 -0 - 50 -0 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -LWPOLYLINE - 5 -994 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3545.073278998258 - 20 -1389.713192906725 - 10 -3989.255620379117 - 20 -1389.713192906725 - 10 -3989.255620379117 - 20 -1027.859286806066 - 10 -3545.073278998258 - 20 -1027.859286806066 - 0 -LWPOLYLINE - 5 -995 -100 -AcDbEntity - 8 -BLK_1_FLR_3_BLT_UP_AREA - 6 -ByLayer - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3372.342164165108 - 20 -1259.280104148725 - 10 -3374.402164170984 - 20 -1259.280104148725 - 10 -3374.402164170984 - 20 -1255.550104161433 - 10 -3372.342164165108 - 20 -1255.550104161433 - 0 -LWPOLYLINE - 5 -996 -100 -AcDbEntity - 8 -BLK_1_FLR_0_BLT_UP_AREA_DEDUCT - 6 -ByLayer - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3300.224476717307 - 20 -1245.352369962667 - 10 -3301.124476717212 - 20 -1245.352369962667 - 10 -3301.124476717087 - 20 -1243.552369962679 - 10 -3300.22410247149 - 20 -1243.552369962679 - 0 -LWPOLYLINE - 5 -997 -100 -AcDbEntity - 8 -BLK_1_FLR_0_BLT_UP_AREA_DEDUCT - 6 -ByLayer - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 1 - 43 -0 - 10 -3302.553122670751 - 20 -1244.552369962679 - 10 -3303.828122670763 - 20 -1244.552369962679 - 10 -3303.828122670763 - 20 -1243.423737554059 - 10 -3303.928122670622 - 20 -1243.423737554059 - 10 -3303.928122670622 - 20 -1242.822369962639 - 10 -3302.523122670595 - 20 -1242.822369962639 - 10 -3302.524476717226 - 20 -1244.252369962649 - 10 -3302.525355745574 - 20 -1244.552369962679 - 0 -LWPOLYLINE - 5 -998 -100 -AcDbEntity - 8 -BLK_1_FLR_1_BLT_UP_AREA_DEDUCT - 6 -ByLayer - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3317.077611773763 - 20 -1245.352369962667 - 10 -3317.977986019338 - 20 -1245.352369962667 - 10 -3317.977986019359 - 20 -1243.552369960936 - 10 -3317.077611773763 - 20 -1243.552369960936 - 0 -LWPOLYLINE - 5 -999 -100 -AcDbEntity - 8 -BLK_1_FLR_1_BLT_UP_AREA_DEDUCT - 6 -ByLayer - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 1 - 43 -0 - 10 -3319.406631973023 - 20 -1244.552369960937 - 10 -3320.681631973035 - 20 -1244.552369960937 - 10 -3320.681631973035 - 20 -1243.423737552317 - 10 -3320.781631972895 - 20 -1243.423737552317 - 10 -3320.781631972895 - 20 -1243.031405693931 - 10 -3319.376631972867 - 20 -1242.822369960897 - 10 -3319.3779860195 - 20 -1244.252369960907 - 10 -3319.378865047845 - 20 -1244.552369960937 - 0 -LWPOLYLINE - 5 -99A -100 -AcDbEntity - 8 -BLK_1_FLR_1_BLT_UP_AREA_DEDUCT - 6 -CONTINUOUS - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3353.288675249576 - 20 -1245.352369962667 - 10 -3354.188675249461 - 20 -1245.352369985618 - 10 -3354.188675250858 - 20 -1243.552369964251 - 10 -3353.288301005261 - 20 -1243.552369964251 - 0 -LWPOLYLINE - 5 -99B -100 -AcDbEntity - 8 -BLK_1_FLR_1_BLT_UP_AREA_DEDUCT - 6 -CONTINUOUS - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 1 - 43 -0 - 10 -3355.617321204522 - 20 -1244.552369964251 - 10 -3356.892321204534 - 20 -1244.552369964251 - 10 -3356.892321204534 - 20 -1243.423737555631 - 10 -3356.992321204394 - 20 -1243.423737555631 - 10 -3356.992321204394 - 20 -1242.822369964211 - 10 -3355.587321204366 - 20 -1242.822369964211 - 10 -3355.588675250998 - 20 -1244.252369964221 - 10 -3355.589554279344 - 20 -1244.552369964251 - 0 -LWPOLYLINE - 5 -99C -100 -AcDbEntity - 8 -BLK_1_FLR_-1_BLT_UP_AREA_DEDUCT - 6 -CONTINUOUS - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 16 - 70 - 1 - 43 -0 - 10 -3281.603068378307 - 20 -1259.050104148725 - 10 -3292.840538748289 - 20 -1259.050104148725 - 10 -3292.840538748287 - 20 -1245.952369962646 - 10 -3293.070538748289 - 20 -1245.952369962644 - 10 -3293.070538748289 - 20 -1243.823737554077 - 10 -3289.610538748287 - 20 -1243.823737554077 - 10 -3289.610538748306 - 20 -1243.623737554299 - 10 -3286.606714331798 - 20 -1243.623737553833 - 10 -3286.606714331777 - 20 -1244.752369962632 - 10 -3284.903068378103 - 20 -1244.752369962632 - 10 -3284.903068378103 - 20 -1245.052369962679 - 10 -3283.703068378148 - 20 -1245.052369962679 - 10 -3283.703068378148 - 20 -1243.552369962679 - 10 -3282.802694132552 - 20 -1243.552369962679 - 10 -3282.802694132552 - 20 -1245.952369962644 - 10 -3281.603068378181 - 20 -1245.952369962646 - 0 -LWPOLYLINE - 5 -99D -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 9 - 70 - 1 - 43 -0 - 10 -3284.903068378103 - 20 -1245.052369962679 - 10 -3283.703068378148 - 20 -1245.052369962679 - 10 -3283.703068378148 - 20 -1243.552369962679 - 10 -3282.803068378242 - 20 -1243.552369962679 - 10 -3282.803068378246 - 20 -1245.952369962644 - 10 -3281.573068378261 - 20 -1245.952369962646 - 10 -3281.573068378261 - 20 -1242.654635776659 - 10 -3281.573067692857 - 20 -1242.352943808457 - 10 -3284.903068378103 - 20 -1242.351804283501 - 0 -LWPOLYLINE - 5 -99E -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3284.903068378103 - 20 -1245.052369962679 - 10 -3283.703068378148 - 20 -1245.052369962679 - 10 -3283.703068378148 - 20 -1243.552369962679 - 10 -3284.903068378103 - 20 -1243.552369962679 - 0 -LWPOLYLINE - 5 -99F -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3283.703068378148 - 20 -1243.552369962679 - 10 -3282.803068378242 - 20 -1243.552369962679 - 10 -3282.803068422602 - 20 -1242.352728218148 - 10 -3283.703068422506 - 20 -1242.352008989147 - 0 -LWPOLYLINE - 5 -9A0 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3282.803068378242 - 20 -1243.552369962679 - 10 -3281.573068378261 - 20 -1243.552369962679 - 10 -3281.573068378261 - 20 -1245.952369962644 - 10 -3282.803068378242 - 20 -1245.952369962644 - 0 -DIMENSION - 5 -9A1 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D24 - 10 -3284.525130626578 - 20 -1243.55236996268 - 30 -0 - 11 -3284.525130626578 - 21 -1244.302369962678 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3284.699090456707 - 23 -1245.052369962679 - 33 -0 - 14 -3284.699090456707 - 24 -1243.552369962679 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9A2 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D25 - 10 -3282.803068392845 - 20 -1243.079906270055 - 30 -0 - 11 -3282.159746428316 - 21 -1243.079906270055 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3283.703068392752 - 23 -1243.15718709081 - 33 -0 - 14 -3282.803068392845 - 24 -1243.15718709081 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9A3 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D26 - 10 -3282.378710914939 - 20 -1245.952369962645 - 30 -0 - 11 -3282.378710914938 - 21 -1244.752369962662 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3282.378710914928 - 23 -1243.552369962679 - 33 -0 - 14 -3282.378710914933 - 24 -1245.952369962645 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9A4 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D27 - 10 -3284.903068378103 - 20 -1245.209053745057 - 30 -0 - 11 -3284.303068378125 - 21 -1245.209053745057 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3283.703068378148 - 23 -1245.052369962679 - 33 -0 - 14 -3284.903068378103 - 24 -1245.052369962679 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9A5 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D28 - 10 -3283.253068378211 - 20 -1242.352368869733 - 30 -0 - 11 -3283.253068378211 - 21 -1242.952369416206 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3283.253068378196 - 23 -1243.552369962679 - 33 -0 - 14 -3283.252335025697 - 24 -1242.352368869733 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9A6 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D29 - 10 -3282.803068378242 - 20 -1243.756682050024 - 30 -0 - 11 -3282.203068378212 - 21 -1243.756682050024 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3281.603068378181 - 23 -1245.952369962646 - 33 -0 - 14 -3282.803068378242 - 24 -1243.552370008162 - 34 -0 -100 -AcDbRotatedDimension - 0 -LWPOLYLINE - 5 -9A7 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 9 - 70 - 1 - 43 -0 - 10 -3302.324476717156 - 20 -1245.652369962656 - 10 -3301.124476717203 - 20 -1245.652369962656 - 10 -3301.124476717212 - 20 -1243.552369962674 - 10 -3300.224476717306 - 20 -1243.552369962674 - 10 -3300.224476717311 - 20 -1247.752369962631 - 10 -3299.024476717244 - 20 -1247.752369962634 - 10 -3299.024476717244 - 20 -1242.654635776654 - 10 -3299.024476717227 - 20 -1242.352369962726 - 10 -3302.324476717166 - 20 -1242.351804283496 - 0 -LWPOLYLINE - 5 -9A8 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3302.324476717166 - 20 -1245.652369962656 - 10 -3301.124476717212 - 20 -1245.652369962656 - 10 -3301.124476717212 - 20 -1243.552369962674 - 10 -3302.324476717166 - 20 -1243.552369962674 - 0 -LWPOLYLINE - 5 -9A9 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3301.124476717212 - 20 -1243.552369962674 - 10 -3300.224476717306 - 20 -1243.552369962674 - 10 -3300.224476761666 - 20 -1242.352728218143 - 10 -3301.124476761569 - 20 -1242.352008989142 - 0 -LWPOLYLINE - 5 -9AA -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3300.224476717306 - 20 -1243.552369962674 - 10 -3299.024476717227 - 20 -1243.552369962674 - 10 -3299.024476717244 - 20 -1247.752369962634 - 10 -3300.224476717306 - 20 -1247.752369962632 - 0 -DIMENSION - 5 -9AB -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D30 - 10 -3301.94653896565 - 20 -1243.552369962674 - 30 -0 - 11 -3301.94653896565 - 21 -1244.602369962665 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3302.120498795771 - 23 -1245.652369962656 - 33 -0 - 14 -3302.120498795771 - 24 -1243.552369962674 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9AC -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D31 - 10 -3300.224476731909 - 20 -1243.079906270047 - 30 -0 - 11 -3299.581154767381 - 21 -1243.079906270047 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3301.124476731815 - 23 -1243.157187090806 - 33 -0 - 14 -3300.224476731909 - 24 -1243.157187090806 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9AD -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D32 - 10 -3299.810469436013 - 20 -1247.752369962632 - 30 -0 - 11 -3299.810469436013 - 21 -1245.652369962653 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3299.81046943599 - 23 -1243.552369962674 - 33 -0 - 14 -3299.810469435998 - 24 -1247.752369962632 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9AE -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D33 - 10 -3302.324476717166 - 20 -1245.809053745033 - 30 -0 - 11 -3301.724476717189 - 21 -1245.809053745033 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3301.124476717212 - 23 -1245.652369962656 - 33 -0 - 14 -3302.324476717166 - 24 -1245.652369962656 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9AF -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D34 - 10 -3300.674476717278 - 20 -1242.352368869728 - 30 -0 - 11 -3300.674476717278 - 21 -1242.952369416201 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3300.674476717258 - 23 -1243.552369962674 - 33 -0 - 14 -3300.673743364761 - 24 -1242.352368869728 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9B0 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D35 - 10 -3300.224476717306 - 20 -1243.756682050019 - 30 -0 - 11 -3299.624476717275 - 21 -1243.756682050019 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3299.024476717244 - 23 -1245.952369962641 - 33 -0 - 14 -3300.224476717306 - 24 -1243.552370652369 - 34 -0 -100 -AcDbRotatedDimension - 0 -LWPOLYLINE - 5 -9B1 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 9 - 70 - 1 - 43 -0 - 10 -3319.177986022085 - 20 -1245.652369962656 - 10 -3317.977986022132 - 20 -1245.652369962656 - 10 -3317.977986022152 - 20 -1243.552369960933 - 10 -3317.077986022245 - 20 -1243.552369960933 - 10 -3317.077611776302 - 20 -1246.852369962666 - 10 -3315.877986022039 - 20 -1246.852369962667 - 10 -3315.877986022039 - 20 -1242.654635774913 - 10 -3315.877986019499 - 20 -1242.352369962726 - 10 -3319.177986022105 - 20 -1242.351804281755 - 0 -LWPOLYLINE - 5 -9B2 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3319.177986022085 - 20 -1245.652369962656 - 10 -3317.977986022132 - 20 -1245.652369962656 - 10 -3317.977986022152 - 20 -1243.552369960933 - 10 -3319.177986022105 - 20 -1243.552369960933 - 0 -LWPOLYLINE - 5 -9B3 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3317.977986022152 - 20 -1243.552369960933 - 10 -3317.077986022245 - 20 -1243.552369960933 - 10 -3317.077986066605 - 20 -1242.352728216402 - 10 -3317.977986066509 - 20 -1242.352008987401 - 0 -LWPOLYLINE - 5 -9B4 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3317.077986022245 - 20 -1243.552369960933 - 10 -3315.877986022039 - 20 -1243.552369960933 - 10 -3315.877986022039 - 20 -1246.852369962667 - 10 -3317.077611760689 - 20 -1246.852507637009 - 0 -DIMENSION - 5 -9B5 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D36 - 10 -3318.800048270567 - 20 -1243.552369960933 - 30 -0 - 11 -3318.800048270566 - 21 -1244.602369961795 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3318.97400810069 - 23 -1245.652369962656 - 33 -0 - 14 -3318.97400810071 - 24 -1243.552369960933 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9B6 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D37 - 10 -3317.077986036848 - 20 -1243.079906268309 - 30 -0 - 11 -3316.43466407232 - 21 -1243.079906268309 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3317.977986036755 - 23 -1243.157187089064 - 33 -0 - 14 -3317.077986036848 - 24 -1243.157187089064 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9B7 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D38 - 10 -3316.663978740904 - 20 -1246.852369962667 - 30 -0 - 11 -3316.663978740903 - 21 -1245.2023699618 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3316.663978740885 - 23 -1243.552369960933 - 33 -0 - 14 -3316.663978740891 - 24 -1246.852369962667 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9B8 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D39 - 10 -3319.177986022085 - 20 -1245.809053745033 - 30 -0 - 11 -3318.577986022108 - 21 -1245.809053745033 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3317.977986022132 - 23 -1245.652369962656 - 33 -0 - 14 -3319.177986022085 - 24 -1245.652369962656 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9B9 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D40 - 10 -3317.527986022219 - 20 -1242.352368867987 - 30 -0 - 11 -3317.527986022219 - 21 -1242.95236941446 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3317.527986022199 - 23 -1243.552369960933 - 33 -0 - 14 -3317.5272526697 - 24 -1242.352368867987 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9BA -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D41 - 10 -3317.077986022245 - 20 -1243.756683315703 - 30 -0 - 11 -3316.477986022214 - 21 -1243.756683315703 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3315.877986022184 - 23 -1245.9523699609 - 33 -0 - 14 -3317.077986022245 - 24 -1243.552371273841 - 34 -0 -100 -AcDbRotatedDimension - 0 -LWPOLYLINE - 5 -9BB -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 9 - 70 - 1 - 43 -0 - 10 -3355.388675249435 - 20 -1245.652369962656 - 10 -3354.188675249481 - 20 -1245.652369962656 - 10 -3354.188675249481 - 20 -1243.552369962674 - 10 -3353.288675249574 - 20 -1243.552369962674 - 10 -3353.288675249579 - 20 -1246.852369962691 - 10 -3352.088675592304 - 20 -1246.852369962691 - 10 -3352.088675592303 - 20 -1242.654635776654 - 10 -3352.088674906898 - 20 -1242.352943808452 - 10 -3355.388675249435 - 20 -1242.351804283496 - 0 -LWPOLYLINE - 5 -9BC -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3355.388675249435 - 20 -1245.652369962656 - 10 -3354.188675249481 - 20 -1245.652369962656 - 10 -3354.188675249481 - 20 -1243.552369962674 - 10 -3355.388675249435 - 20 -1243.552369962674 - 0 -LWPOLYLINE - 5 -9BD -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3354.188675249481 - 20 -1243.552369962674 - 10 -3353.288675249574 - 20 -1243.552369962674 - 10 -3353.288675293935 - 20 -1242.352728218143 - 10 -3354.188675293838 - 20 -1242.352008989142 - 0 -LWPOLYLINE - 5 -9BE -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3353.288675249574 - 20 -1243.552369962674 - 10 -3352.088675249515 - 20 -1243.552369962674 - 10 -3352.088675249515 - 20 -1246.852369962691 - 10 -3353.288675249575 - 20 -1246.852369962691 - 0 -DIMENSION - 5 -9BF -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D42 - 10 -3355.010737497922 - 20 -1243.552369962674 - 30 -0 - 11 -3355.010737497922 - 21 -1244.602369962665 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3355.18469732804 - 23 -1245.652369962656 - 33 -0 - 14 -3355.18469732804 - 24 -1243.552369962674 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9C0 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D43 - 10 -3353.288675264177 - 20 -1243.079906270047 - 30 -0 - 11 -3352.645353299648 - 21 -1243.079906270047 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3354.188675264084 - 23 -1243.157187090806 - 33 -0 - 14 -3353.288675264177 - 24 -1243.157187090806 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9C1 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D44 - 10 -3352.874667968283 - 20 -1246.852369962691 - 30 -0 - 11 -3352.874667968283 - 21 -1245.202369962683 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3352.874667968265 - 23 -1243.552369962674 - 33 -0 - 14 -3352.874667968265 - 24 -1246.852369962691 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9C2 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D45 - 10 -3355.388675249435 - 20 -1245.809053745032 - 30 -0 - 11 -3354.788675249458 - 21 -1245.809053745032 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3354.188675249481 - 23 -1245.652369962656 - 33 -0 - 14 -3355.388675249435 - 24 -1245.652369962656 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9C3 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D46 - 10 -3353.738675249547 - 20 -1242.352368869728 - 30 -0 - 11 -3353.738675249547 - 21 -1242.952369416201 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3353.738675249528 - 23 -1243.552369962674 - 33 -0 - 14 -3353.73794189703 - 24 -1242.352368869728 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9C4 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D47 - 10 -3353.288675249574 - 20 -1243.75668465645 - 30 -0 - 11 -3352.688675249544 - 21 -1243.75668465645 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3352.088675249515 - 23 -1245.952369962641 - 33 -0 - 14 -3353.288675249574 - 24 -1243.552372614588 - 34 -0 -100 -AcDbRotatedDimension - 0 -LINE - 5 -9C5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1245.052369962633 - 11 -3319.177986022085 - 21 -1245.052369962633 - 0 -LINE - 5 -9C6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1246.552369962691 - 11 -3352.088675249601 - 21 -1246.552369962691 - 0 -LINE - 5 -9C7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1246.852369962691 - 11 -3352.088675249601 - 21 -1246.852369962691 - 0 -LWPOLYLINE - 5 -9C8 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_LIFT_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3285.131714331685 - 20 -1244.552369962679 - 10 -3286.406714331592 - 20 -1244.552369962679 - 10 -3286.406714331592 - 20 -1242.922369962616 - 10 -3285.131714331685 - 20 -1242.922369962616 - 0 -LWPOLYLINE - 5 -9C9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3302.553122670751 - 20 -1244.552369962679 - 10 -3303.828122670763 - 20 -1244.552369962679 - 10 -3303.828122670763 - 20 -1242.922369962616 - 10 -3302.553122670751 - 20 -1242.922369962616 - 0 -LWPOLYLINE - 5 -9CA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3319.406631977007 - 20 -1244.552369960937 - 10 -3320.631631975528 - 20 -1244.552369960937 - 10 -3320.631631975528 - 20 -1242.972369962663 - 10 -3319.406631977007 - 20 -1242.972369962663 - 0 -LWPOLYLINE - 5 -9CB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3355.617321202998 - 20 -1244.552369962679 - 10 -3356.892321203137 - 20 -1244.552369962679 - 10 -3356.892321203137 - 20 -1242.922369962675 - 10 -3355.617321202998 - 20 -1242.922369962675 - 0 -MTEXT - 5 -9CC -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3283.268677616787 - 20 -1245.901766790177 - 30 -0 - 40 -0.18509765625 - 41 -2.118339843750011 - 71 - 1 - 72 - 5 - 1 -FLR_HT_M=2.85 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -9CD -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3300.725937942232 - 20 -1247.318089485752 - 30 -0 - 40 -0.18509765625 - 41 -2.138906250000011 - 71 - 1 - 72 - 5 - 1 -FLR_HT_M=4.05 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -9CE -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3317.252281568243 - 20 -1247.005921261956 - 30 -0 - 40 -0.18509765625 - 41 -1.974375000000023 - 71 - 1 - 72 - 5 - 1 -FLR_HT_M=3.6 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -9CF -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3353.879127852625 - 20 -1246.95928062544 - 30 -0 - 40 -0.18509765625 - 41 -1.974375000000023 - 71 - 1 - 72 - 5 - 1 -FLR_HT_M=3.6 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -9D0 -100 -AcDbEntity - 8 -RWH - 6 -ByLayer - 62 - 8 -370 - -1 -100 -AcDbMText - 10 -3699.013859384949 - 20 -1111.516430563994 - 30 -0 - 40 -0.35 - 41 -5.98888888888891 - 71 - 1 - 72 - 5 - 1 -RWH_CAPACITY_L=5000 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -9D1 -100 -AcDbEntity - 8 -RWH - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3699.862406253502 - 20 -1113.369687750055 - 10 -3703.861797786857 - 20 -1113.43945423812 - 10 -3703.925296166536 - 20 -1111.910678144355 - 10 -3699.925752516535 - 20 -1111.858353278301 - 0 -LWPOLYLINE - 5 -9D2 -100 -AcDbEntity - 8 -WASTE_DISPOSAL - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3707.312411874112 - 20 -1129.276287099953 - 10 -3709.588790924883 - 20 -1129.274351026701 - 10 -3709.585205604046 - 20 -1127.324354322738 - 10 -3707.310799102231 - 20 -1127.326286769203 - 0 -LWPOLYLINE - 5 -9D3 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 1 - 43 -0 - 10 -3298.794476717245 - 20 -1259.280104148715 - 10 -3300.624476717086 - 20 -1259.280104148715 - 10 -3300.624476717086 - 20 -1256.300104148744 - 10 -3299.874476717086 - 20 -1256.300104148744 - 10 -3299.874476717086 - 20 -1258.300104148744 - 10 -3299.774476717227 - 20 -1258.300104148744 - 10 -3299.774476717227 - 20 -1256.300104148744 - 10 -3298.794476717245 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -9D4 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 1 - 43 -0 - 10 -3315.647986019496 - 20 -1259.280104146958 - 10 -3317.477986019337 - 20 -1259.280104146958 - 10 -3317.477986019337 - 20 -1256.300104146987 - 10 -3316.727986019337 - 20 -1256.300104146987 - 10 -3316.727986019337 - 20 -1258.300104146987 - 10 -3316.627986019477 - 20 -1258.300104146987 - 10 -3316.627986019477 - 20 -1256.300104146987 - 10 -3315.647986019496 - 20 -1256.300104146987 - 0 -LWPOLYLINE - 5 -9D5 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 1 - 43 -0 - 10 -3351.858675251249 - 20 -1259.280104121939 - 10 -3353.688675251091 - 20 -1259.280104121939 - 10 -3353.688675251091 - 20 -1256.300104121969 - 10 -3352.938675251091 - 20 -1256.300104121969 - 10 -3352.938675251091 - 20 -1258.300104121969 - 10 -3352.838675251231 - 20 -1258.300104121969 - 10 -3352.838675251231 - 20 -1256.300104121969 - 10 -3351.858675251249 - 20 -1256.300104121969 - 0 -LWPOLYLINE - 5 -9D6 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3299.024476717227 - 20 -1258.300104148744 - 10 -3299.774476717227 - 20 -1258.300104148744 - 10 -3299.774476717227 - 20 -1256.300104148744 - 10 -3299.024476717227 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -9D7 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3299.874476717086 - 20 -1256.300104148744 - 10 -3300.624476717086 - 20 -1256.300104148744 - 10 -3300.624476717086 - 20 -1258.300104148744 - 10 -3299.874476717086 - 20 -1258.300104148744 - 0 -LWPOLYLINE - 5 -9D8 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3315.877986019477 - 20 -1258.300104148744 - 10 -3316.627986019477 - 20 -1258.300104148744 - 10 -3316.627986019477 - 20 -1256.300104148744 - 10 -3315.877986019477 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -9D9 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3316.727986019337 - 20 -1256.300104148744 - 10 -3317.477986019337 - 20 -1256.300104148744 - 10 -3317.477986019337 - 20 -1258.300104148744 - 10 -3316.727986019337 - 20 -1258.300104148744 - 0 -LWPOLYLINE - 5 -9DA -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3352.088675251034 - 20 -1258.300104171694 - 10 -3352.838675251034 - 20 -1258.300104171694 - 10 -3352.838675251034 - 20 -1256.300104171695 - 10 -3352.088675251034 - 20 -1256.300104171695 - 0 -LWPOLYLINE - 5 -9DB -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3352.938675250895 - 20 -1256.300104171695 - 10 -3353.688675250895 - 20 -1256.300104171695 - 10 -3353.688675250895 - 20 -1258.300104171694 - 10 -3352.938675250895 - 20 -1258.300104171694 - 0 -LWPOLYLINE - 5 -9DC -100 -AcDbEntity - 8 -BLK_1_FLR_3_FIRESTAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3372.3421641686 - 20 -1259.280104148725 - 10 -3374.402164174477 - 20 -1259.280104148725 - 10 -3374.402164174477 - 20 -1255.550104161433 - 10 -3372.3421641686 - 20 -1255.550104161433 - 0 -DIMENSION - 5 -9DD -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D48 - 10 -3353.434456956947 - 20 -1256.300104121969 - 30 -0 - 11 -3353.434456956946 - 21 -1257.300104146831 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3353.313675250895 - 23 -1258.300104171694 - 33 -0 - 14 -3353.313675250895 - 24 -1256.300104121969 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9DE -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D49 - 10 -3352.348675251248 - 20 -1256.300104121969 - 30 -0 - 11 -3352.348675251248 - 21 -1257.300104146832 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3352.321976650384 - 23 -1258.300104171694 - 33 -0 - 14 -3352.348675251239 - 24 -1256.300104121969 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9DF -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D50 - 10 -3353.688675251091 - 20 -1258.430923504448 - 30 -0 - 11 -3354.33199721562 - 21 -1258.430923504448 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3352.938675249461 - 23 -1258.300104171694 - 33 -0 - 14 -3353.688675251091 - 24 -1258.300104171694 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9E0 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D51 - 10 -3352.088675251034 - 20 -1258.458460622718 - 30 -0 - 11 -3351.445353286505 - 21 -1258.458460622718 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3352.838675251231 - 23 -1258.300104121969 - 33 -0 - 14 -3352.088675251034 - 24 -1258.300104121969 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9E1 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D52 - 10 -3317.223767729391 - 20 -1256.300104121969 - 30 -0 - 11 -3317.223767729391 - 21 -1257.300104146831 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3317.102986023332 - 23 -1258.300104171694 - 33 -0 - 14 -3317.102986023332 - 24 -1256.300104121969 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9E2 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D53 - 10 -3316.137986023692 - 20 -1256.300104121969 - 30 -0 - 11 -3316.137986023692 - 21 -1257.300104146831 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3316.111287422821 - 23 -1258.300104171694 - 33 -0 - 14 -3316.137986023678 - 24 -1256.300104121969 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9E3 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D54 - 10 -3317.477986023528 - 20 -1258.430923504448 - 30 -0 - 11 -3318.121307988058 - 21 -1258.430923504448 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3316.727986021899 - 23 -1258.300104171694 - 33 -0 - 14 -3317.477986023528 - 24 -1258.300104171694 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9E4 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D55 - 10 -3315.877986023473 - 20 -1258.458460622718 - 30 -0 - 11 -3315.234664058943 - 21 -1258.458460622718 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3316.627986023668 - 23 -1258.300104121969 - 33 -0 - 14 -3315.877986023473 - 24 -1258.300104121969 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9E5 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D56 - 10 -3300.370258424579 - 20 -1256.300104121969 - 30 -0 - 11 -3300.370258424579 - 21 -1257.300104146831 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3300.24947671852 - 23 -1258.300104171694 - 33 -0 - 14 -3300.24947671852 - 24 -1256.300104121969 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9E6 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D57 - 10 -3299.28447671888 - 20 -1256.300104121969 - 30 -0 - 11 -3299.28447671888 - 21 -1257.300104146831 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3299.257778118009 - 23 -1258.300104171694 - 33 -0 - 14 -3299.284476718866 - 24 -1256.300104121969 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9E7 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D58 - 10 -3300.624476718716 - 20 -1258.430923504448 - 30 -0 - 11 -3301.267798683246 - 21 -1258.430923504448 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3299.874476717086 - 23 -1258.300104171694 - 33 -0 - 14 -3300.624476718716 - 24 -1258.300104171694 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9E8 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D59 - 10 -3299.02447671866 - 20 -1258.458460622718 - 30 -0 - 11 -3298.381154754131 - 21 -1258.458460622718 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3299.774476718857 - 23 -1258.300104121969 - 33 -0 - 14 -3299.02447671866 - 24 -1258.300104121969 - 34 -0 -100 -AcDbRotatedDimension - 0 -MTEXT - 5 -9E9 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3299.840522810782 - 20 -1255.255954826638 - 30 -0 - 40 -0.18509765625 - 41 -2.138906250000011 - 71 - 1 - 72 - 5 - 1 -FLR_HT_M=4.05 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -9EA -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3316.430967205997 - 20 -1255.075127179796 - 30 -0 - 40 -0.18509765625 - 41 -1.974375000000023 - 71 - 1 - 72 - 5 - 1 -FLR_HT_M=3.6 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -9EB -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3352.076468809833 - 20 -1255.935428104983 - 30 -0 - 40 -0.18509765625 - 41 -1.974375000000023 - 71 - 1 - 72 - 5 - 1 -FLR_HT_M=3.6 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -9EC -100 -AcDbEntity - 8 -BLK_1_FLR_0_SP_WC - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3300.774476717226 - 20 -1259.050104148744 - 10 -3302.724476717179 - 20 -1259.050104148744 - 10 -3302.724476717179 - 20 -1257.550104148744 - 10 -3300.774476717226 - 20 -1257.550104148744 - 0 -LWPOLYLINE - 5 -9ED -100 -AcDbEntity - 8 -BLK_1_FLR_0_WATER_CLOSET - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3302.774476717227 - 20 -1259.050104148744 - 10 -3303.840016419767 - 20 -1259.050104148744 - 10 -3303.840016419767 - 20 -1257.550104148744 - 10 -3302.774476717227 - 20 -1257.550104148744 - 0 -LWPOLYLINE - 5 -9EE -100 -AcDbEntity - 8 -BLK_1_FLR_0_WATER_CLOSET - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3301.774179179687 - 20 -1256.048735667427 - 10 -3300.774476717226 - 20 -1256.048735667427 - 10 -3300.774476717226 - 20 -1257.500104145787 - 10 -3301.774179179687 - 20 -1257.500104145787 - 0 -LWPOLYLINE - 5 -9EF -100 -AcDbEntity - 8 -BLK_1_FLR_1_WATER_CLOSET - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3319.627986019477 - 20 -1259.050104146998 - 10 -3320.693525722017 - 20 -1259.050104146998 - 10 -3320.693525722017 - 20 -1257.550104146998 - 10 -3319.627986019477 - 20 -1257.550104146998 - 0 -LWPOLYLINE - 5 -9F0 -100 -AcDbEntity - 8 -BLK_1_FLR_1_WATER_CLOSET - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3318.62798602204 - 20 -1256.048735665681 - 10 -3317.627986019477 - 20 -1256.048735665681 - 10 -3317.627986019477 - 20 -1257.500104144041 - 10 -3318.62798602204 - 20 -1257.500104144041 - 0 -DIMENSION - 5 -9F1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D60 - 10 -3320.693525724812 - 20 -1257.851297607682 - 30 -0 - 11 -3320.161621811486 - 21 -1257.851297607682 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3319.629717898161 - 23 -1257.867062992372 - 33 -0 - 14 -3320.693525724812 - 24 -1257.867062992372 - 34 -0 -100 -AcDbRotatedDimension - 0 -MTEXT - 5 -9F2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3301.203108666742 - 20 -1258.814638991693 - 30 -0 - 40 -0.18 - 41 -2.844999961839636 - 71 - 1 - 72 - 5 - 1 -\pt2.52;DISABLE TOILET\P1.95X1.50 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 --0.008873397653922362 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -9F3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3301.054003263868 - 20 -1256.496157512387 - 30 -0 - 40 -0.18 - 41 -1.250000000000011 - 71 - 1 - 72 - 5 - 1 -\pt2.52;WC\P1.45X1.00 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -9F4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3302.872769241266 - 20 -1258.423469386382 - 30 -0 - 40 -0.18 - 41 -1.190000000000011 - 71 - 1 - 72 - 5 - 1 -\pt252;WC\P1.06X1.50 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 --0.008873397653922366 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -9F5 -100 -AcDbEntity - 8 -BLK_1_FLR_0_WASH - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3303.840016419767 - 20 -1257.416490417573 - 10 -3303.501700788219 - 20 -1257.416490417573 - 10 -3303.501700788219 - 20 -1257.012183984098 - 10 -3303.840016419767 - 20 -1257.012183984098 - 0 -LWPOLYLINE - 5 -9F6 -100 -AcDbEntity - 8 -BLK_1_FLR_0_WASH - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3303.840016419767 - 20 -1257.012183984098 - 10 -3303.501700788219 - 20 -1257.012183984098 - 10 -3303.501700788219 - 20 -1256.607877550622 - 10 -3303.840016419767 - 20 -1256.607877550622 - 0 -LWPOLYLINE - 5 -9F7 -100 -AcDbEntity - 8 -BLK_1_FLR_0_WASH - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3303.840016419767 - 20 -1258.16588586402 - 10 -3303.527572195436 - 20 -1258.16588586402 - 10 -3303.527572195436 - 20 -1257.761579430545 - 10 -3303.840016419767 - 20 -1257.761579430545 - 0 -LWPOLYLINE - 5 -9F8 -100 -AcDbEntity - 8 -BLK_1_FLR_0_WASH - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3302.219690062577 - 20 -1258.715224104448 - 10 -3302.666040622906 - 20 -1258.715224104448 - 10 -3302.666040622906 - 20 -1259.050104148744 - 10 -3302.219690062577 - 20 -1259.050104148744 - 0 -LWPOLYLINE - 5 -9F9 -100 -AcDbEntity - 8 -BLK_1_FLR_0_WASH - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3301.09647760688 - 20 -1257.499237734466 - 10 -3300.774476717226 - 20 -1257.500104145787 - 10 -3300.774476717226 - 20 -1256.990234874014 - 10 -3301.09647760688 - 20 -1256.989368462692 - 0 -LWPOLYLINE - 5 -9FA -100 -AcDbEntity - 8 -BLK_1_FLR_1_WASH - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3320.693525721927 - 20 -1258.175063545055 - 10 -3320.366959814676 - 20 -1258.175063545055 - 10 -3320.366959814676 - 20 -1257.77075711158 - 10 -3320.693525721927 - 20 -1257.77075711158 - 0 -LWPOLYLINE - 5 -9FB -100 -AcDbEntity - 8 -BLK_1_FLR_1_WASH - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3317.938974262997 - 20 -1257.500104144041 - 10 -3317.627986019477 - 20 -1257.500104144041 - 10 -3317.627986019477 - 20 -1256.995619385907 - 10 -3317.938974262997 - 20 -1256.995619385907 - 0 -LWPOLYLINE - 5 -9FC -100 -AcDbEntity - 8 -BLK_1_FLR_1_WASH - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3320.693525724812 - 20 -1256.056414286734 - 10 -3320.693525724812 - 20 -1256.50374874116 - 10 -3320.379812578121 - 20 -1256.50374874116 - 10 -3320.379812578121 - 20 -1256.056414286734 - 0 -INSERT - 5 -9FD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbBlockReference - 2 -15 - 10 --4419.017518747216 - 20 -410.517336000665 - 30 -0 - 41 --0.0105407388858543 - 42 -0.0105407388858543 - 43 -0 - 50 -0.0088733995148438 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -LWPOLYLINE - 5 -9FE -100 -AcDbEntity - 8 -BLK_1_FLR_1_WATER_CLOSET - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3317.627986019477 - 20 -1259.050104146998 - 10 -3319.577986019432 - 20 -1259.050104146998 - 10 -3319.577986019432 - 20 -1257.550104146998 - 10 -3317.627986019477 - 20 -1257.550104146998 - 0 -LWPOLYLINE - 5 -9FF -100 -AcDbEntity - 8 -BLK_1_FLR_0_WATER_CLOSET - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3300.774476717226 - 20 -1259.050104148744 - 10 -3302.724476717179 - 20 -1259.050104148744 - 10 -3302.724476717179 - 20 -1257.550104148744 - 10 -3300.774476717226 - 20 -1257.550104148744 - 0 -LWPOLYLINE - 5 -A00 -100 -AcDbEntity - 8 -BLK_1_FLR_0_WASH - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3303.840016419767 - 20 -1256.607877550622 - 10 -3303.501700788219 - 20 -1256.607877550622 - 10 -3303.501700788219 - 20 -1256.203571117147 - 10 -3303.840016419767 - 20 -1256.203571117147 - 0 -INSERT - 5 -A01 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3300.764064482679 - 20 -1257.238723462275 - 30 -0 - 41 --0.5904899999997463 - 42 -0.5904900000003975 - 43 -0 - 50 -89.95617518206222 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -A02 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3302.441257043189 - 20 -1259.05429657233 - 30 -0 - 41 --0.5904899999997461 - 42 -0.5904900000003975 - 43 -0 - 50 -359.9561751820622 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -A03 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3303.840016419676 - 20 -1257.96100172704 - 30 -0 - 41 --0.5904899999997453 - 42 -0.5904900000003975 - 43 -0 - 50 -269.9561751820622 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -A04 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3303.857033020101 - 20 -1257.240480225716 - 30 -0 - 41 --0.5904899999997452 - 42 -0.5904900000003975 - 43 -0 - 50 -269.9561751820622 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -A05 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3303.857033020101 - 20 -1256.431867358765 - 30 -0 - 41 --0.5904899999997452 - 42 -0.5904900000003975 - 43 -0 - 50 -269.9561751820622 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -A06 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3303.857033020101 - 20 -1256.836173792241 - 30 -0 - 41 --0.5904899999997452 - 42 -0.5904900000003975 - 43 -0 - 50 -269.9561751820622 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -A07 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3317.61757378493 - 20 -1257.238723460529 - 30 -0 - 41 --0.5904899999997462 - 42 -0.5904900000003975 - 43 -0 - 50 -89.95617518206222 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -A08 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3320.693525721927 - 20 -1257.961001725294 - 30 -0 - 41 --0.5904899999997452 - 42 -0.5904900000003975 - 43 -0 - 50 -269.9561751820622 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -A09 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3320.700460489955 - 20 -1256.257469881089 - 30 -0 - 41 --0.5904899999997451 - 42 -0.5904900000003975 - 43 -0 - 50 -269.9561751820622 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -LWPOLYLINE - 5 -A0A -100 -AcDbEntity - 8 -PARKING_SLOT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3699.480879126581 - 20 -1130.651148569201 - 10 -3705.530442953199 - 20 -1130.661329416645 - 10 -3705.512340866686 - 20 -1127.631876057222 - 10 -3699.462777040068 - 20 -1127.621695209778 - 0 -LWPOLYLINE - 5 -A0B -100 -AcDbEntity - 8 -PARKING_SLOT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3699.480540771053 - 20 -1127.171011960395 - 10 -3705.53010459767 - 20 -1127.181192807839 - 10 -3705.512002511158 - 20 -1124.151739448416 - 10 -3699.46243868454 - 20 -1124.141558600972 - 0 -LWPOLYLINE - 5 -A0C -100 -AcDbEntity - 8 -PARKING_SLOT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3699.462439489231 - 20 -1124.141693268994 - 10 -3705.512003315851 - 20 -1124.151874116438 - 10 -3705.493901229337 - 20 -1121.122420757015 - 10 -3699.444337402718 - 20 -1121.112239909571 - 0 -LWPOLYLINE - 5 -A0D -100 -AcDbEntity - 8 -PARKING_SLOT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3705.89207145331 - 20 -1114.565780762474 - 10 -3706.904327932729 - 20 -1108.682671348149 - 10 -3703.931686830365 - 20 -1108.105042622127 - 10 -3702.902730137132 - 20 -1114.074096068953 - 0 -LWPOLYLINE - 5 -A0E -100 -AcDbEntity - 8 -DA_PARKING - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3698.227108530828 - 20 -1113.767276560903 - 10 -3701.827108530828 - 20 -1113.767276560903 - 10 -3701.827108530828 - 20 -1107.767276560903 - 10 -3698.227108530828 - 20 -1107.767276560903 - 0 -LWPOLYLINE - 5 -A0F -100 -AcDbEntity - 8 -PARKING_SLOT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3699.445660909198 - 20 -1120.800800139392 - 10 -3705.495224735816 - 20 -1120.810980986836 - 10 -3705.477122649303 - 20 -1117.781527627413 - 10 -3699.427558822686 - 20 -1117.771346779969 - 0 -DIMENSION - 5 -A10 -100 -AcDbEntity - 8 -DA_PARKING - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D61 - 10 -3706.018728615696 - 20 -1114.60003452436 - 30 -0 - 11 -3704.588874033686 - 21 -1113.96528608603 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3702.961422993541 - 23 -1113.775649733043 - 33 -0 - 14 -3705.821132157561 - 24 -1115.045146609702 - 34 -0 - 0 -LWPOLYLINE - 5 -A11 -100 -AcDbEntity - 8 -TWO_WHEELER_PARKING - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3710.700245165523 - 20 -1130.671118105119 - 10 -3708.494483323179 - 20 -1130.671118105119 - 10 -3708.494483323179 - 20 -1118.903961396441 - 10 -3710.700247388511 - 20 -1118.903961396441 - 0 -LWPOLYLINE - 5 -A12 -100 -AcDbEntity - 8 -BLK_1_SHADE_OVERHANG - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3699.233813344707 - 20 -1113.873383950561 - 10 -3699.233845640707 - 20 -1113.342721690382 - 10 -3707.700247410191 - 20 -1113.342721690382 - 10 -3707.700247410191 - 20 -1115.445266810411 - 0 -DIMENSION - 5 -A13 -100 -AcDbEntity - 8 -DIST_EXIT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D62 - 10 -3309.954155061942 - 20 -1250.746552551918 - 30 -0 - 11 -3305.135419876862 - 21 -1253.22399361534 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3300.624476717086 - 23 -1256.300104121969 - 33 -0 - 14 -3310.261947087246 - 24 -1251.345221995126 - 34 -0 - 0 -DIMENSION - 5 -A14 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D63 - 10 -3284.905368613425 - 20 -1245.562005819791 - 30 -0 - 11 -3284.305380836144 - 21 -1245.564713857421 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3283.703068378148 - 23 -1245.052369962679 - 33 -0 - 14 -3284.903043932711 - 24 -1245.046953887419 - 34 -0 - 0 -DIMENSION - 5 -A15 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D64 - 10 -3300.624476717086 - 20 -1256.163161899994 - 30 -0 - 11 -3301.268351205492 - 21 -1256.163161899994 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3299.874476717086 - 23 -1256.300104148744 - 33 -0 - 14 -3300.624476717086 - 24 -1256.300104148744 - 34 -0 - 0 -DIMENSION - 5 -A16 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_DOOR - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D65 - 10 -3307.031947087351 - 20 -1243.673737554059 - 30 -0 - 11 -3305.530034879041 - 21 -1243.673737554059 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3304.02812267073 - 23 -1243.638737554058 - 33 -0 - 14 -3307.031947087351 - 24 -1243.638737554058 - 34 -0 - 0 -DIMENSION - 5 -A17 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D66 - 10 -3302.324476717273 - 20 -1246.220390913326 - 30 -0 - 11 -3301.72447671718 - 21 -1246.220390913326 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3301.124476717087 - 23 -1245.352369962667 - 33 -0 - 14 -3302.324476717273 - 24 -1245.352369962667 - 34 -0 - 0 -DIMENSION - 5 -A18 -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D67 - 10 -3317.477986019337 - 20 -1256.163161899994 - 30 -0 - 11 -3318.121860507742 - 21 -1256.163161899994 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3316.727986019337 - 23 -1256.300104148744 - 33 -0 - 14 -3317.477986019337 - 24 -1256.300104148744 - 34 -0 - 0 -DIMENSION - 5 -A19 -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D68 - 10 -3319.177986019524 - 20 -1246.220390913326 - 30 -0 - 11 -3318.577986019431 - 21 -1246.220390913326 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3317.977986019338 - 23 -1245.352369962667 - 33 -0 - 14 -3319.177986019524 - 24 -1245.352369962667 - 34 -0 - 0 -DIMENSION - 5 -A1A -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D69 - 10 -3353.688675249461 - 20 -1256.163161922944 - 30 -0 - 11 -3354.332549737865 - 21 -1256.163161922944 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3352.938675249461 - 23 -1256.300104171695 - 33 -0 - 14 -3353.688675249461 - 24 -1256.300104171695 - 34 -0 - 0 -DIMENSION - 5 -A1B -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D70 - 10 -3355.388675249648 - 20 -1246.220390936277 - 30 -0 - 11 -3354.788675249555 - 21 -1246.220390936277 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3354.188675249461 - 23 -1245.352369985618 - 33 -0 - 14 -3355.388675249648 - 24 -1245.352369985618 - 34 -0 - 0 -DIMENSION - 5 -A1C -100 -AcDbEntity - 8 -BLK_1_FLR_3_EXIT_WIDTH_DOOR - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D71 - 10 -3374.172164166812 - 20 -1255.730104163693 - 30 -0 - 11 -3373.572164166812 - 21 -1255.730104163693 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3372.972164166813 - 23 -1255.550104162563 - 33 -0 - 14 -3374.172164166812 - 24 -1255.730104162563 - 34 -0 -100 -AcDbRotatedDimension - 0 -LWPOLYLINE - 5 -A1D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3281.621170464698 - 20 -1259.049291753751 - 10 -3287.621170464697 - 20 -1259.049291753751 - 10 -3287.621170464697 - 20 -1256.049291753751 - 10 -3281.621170464698 - 20 -1256.049291753751 - 0 -LWPOLYLINE - 5 -A1E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3281.627027190037 - 20 -1255.55000842973 - 10 -3287.627027190037 - 20 -1255.55000842973 - 10 -3287.627027190037 - 20 -1252.55000842973 - 10 -3281.627027190037 - 20 -1252.55000842973 - 0 -LWPOLYLINE - 5 -A1F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3281.618487474098 - 20 -1252.520705829546 - 10 -3287.618487474098 - 20 -1252.520705829546 - 10 -3287.618487474098 - 20 -1249.520705829546 - 10 -3281.618487474098 - 20 -1249.520705829546 - 0 -LWPOLYLINE - 5 -A20 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3281.623068378183 - 20 -1249.360104148715 - 10 -3287.623068378183 - 20 -1249.360104148715 - 10 -3287.623068378183 - 20 -1246.360104148715 - 10 -3281.623068378183 - 20 -1246.360104148715 - 0 -LWPOLYLINE - 5 -A21 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3470.160100466838 - 20 -1246.986620183514 - 10 -3475.636187167638 - 20 -1246.986620183514 - 0 -LINE - 5 -A22 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3458.752670446676 - 20 -1248.186620183584 - 11 -3467.820140816769 - 21 -1248.186620183584 - 0 -LINE - 5 -A23 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3470.160100466838 - 20 -1246.986620183514 - 11 -3457.965393430237 - 21 -1246.986620183514 - 0 -LINE - 5 -A24 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3464.586316400124 - 20 -1248.186620183525 - 11 -3467.590140816788 - 21 -1248.186620183525 - 0 -LINE - 5 -A25 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3464.586316400124 - 20 -1248.186620183525 - 11 -3467.590140816788 - 21 -1248.186620183525 - 0 -LINE - 5 -A26 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3464.586316400124 - 20 -1248.336620183549 - 11 -3467.590140816788 - 21 -1248.336620183549 - 0 -LINE - 5 -A27 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3464.586316400124 - 20 -1248.486620183514 - 11 -3467.590140816788 - 21 -1248.486620183514 - 0 -LINE - 5 -A28 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3464.586316400124 - 20 -1248.636620183537 - 11 -3467.590140816788 - 21 -1248.636620183537 - 0 -HATCH - 5 -A29 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3471.050140817417 - 20 -1249.969758161813 - 11 -3471.050140817417 - 21 -1256.28662018356 - 72 - 1 - 10 -3471.050140817417 - 20 -1256.28662018356 - 11 -3467.820140817236 - 21 -1256.28662018356 - 72 - 1 - 10 -3467.820140817236 - 20 -1256.28662018356 - 11 -3467.820140817236 - 21 -1249.969758161813 - 72 - 1 - 10 -3467.820140817236 - 20 -1249.969758161813 - 11 -3471.050140817417 - 21 -1249.969758161813 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -1.199999999999999 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -HATCH - 5 -A2A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3464.586316400011 - 20 -1251.48662018363 - 11 -3463.112670446662 - 21 -1251.48662018363 - 72 - 1 - 10 -3463.112670446662 - 20 -1251.48662018363 - 11 -3463.112670446662 - 21 -1248.186620183584 - 72 - 1 - 10 -3463.112670446662 - 20 -1248.186620183584 - 11 -3464.586316400011 - 21 -1248.186620183584 - 72 - 1 - 10 -3464.586316400011 - 20 -1248.186620183584 - 11 -3464.586316400011 - 21 -1251.48662018363 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -1.199999999999999 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -HATCH - 5 -A2B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3464.586316400124 - 20 -1256.28662018356 - 11 -3463.112670446662 - 21 -1256.28662018356 - 72 - 1 - 10 -3463.112670446662 - 20 -1256.28662018356 - 11 -3463.112670446662 - 21 -1251.636620183595 - 72 - 1 - 10 -3463.112670446662 - 20 -1251.636620183595 - 11 -3464.586316400011 - 21 -1251.636620183595 - 72 - 1 - 10 -3464.586316400011 - 20 -1251.636620183595 - 11 -3464.586316400124 - 21 -1256.28662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -1.199999999999999 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -LINE - 5 -A2C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3456.165727321906 - 20 -1248.186620183584 - 11 -3467.820140816769 - 21 -1248.186620183584 - 0 -LINE - 5 -A2D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3456.230352529125 - 20 -1247.975084647481 - 11 -3467.820140816886 - 21 -1247.975084647481 - 0 -LINE - 5 -A2E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3455.807058111215 - 20 -1247.816432995434 - 11 -3467.820140816886 - 21 -1247.816432995434 - 0 -LINE - 5 -A2F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3456.086294557584 - 20 -1247.569641536746 - 11 -3467.820140816886 - 21 -1247.569641536746 - 0 -LINE - 5 -A30 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3456.124973958275 - 20 -1247.269966194002 - 11 -3467.820140816886 - 21 -1247.269966194002 - 0 -LWPOLYLINE - 5 -A31 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3462.882670446765 - 20 -1260.786620183557 - 10 -3462.882670446765 - 20 -1261.98662018351 - 10 -3464.586316400208 - 20 -1261.98662018351 - 10 -3464.586316400011 - 20 -1256.586620183549 - 0 -LWPOLYLINE - 5 -A32 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3464.586316400124 - 20 -1256.28662018356 - 10 -3464.586316400011 - 20 -1251.636620183595 - 0 -LWPOLYLINE - 5 -A33 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3471.050140817417 - 20 -1256.286620183557 - 10 -3471.050140817417 - 20 -1246.98662018351 - 0 -LWPOLYLINE - 5 -A34 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3459.582670447184 - 20 -1251.486620183626 - 10 -3467.820140817203 - 20 -1251.486620183626 - 10 -3467.820140817203 - 20 -1251.636620183592 - 10 -3459.582670447184 - 20 -1251.636620183592 - 0 -LWPOLYLINE - 5 -A35 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3467.590140816672 - 20 -1248.636620183595 - 10 -3467.590140816672 - 20 -1251.48662018363 - 10 -3467.820140817236 - 20 -1251.48662018363 - 10 -3467.820140817236 - 20 -1246.98662018363 - 0 -LWPOLYLINE - 5 -A36 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3464.586316399835 - 20 -1260.78662018356 - 10 -3470.750140817371 - 20 -1260.786620183557 - 10 -3471.050140817417 - 20 -1260.786620183557 - 10 -3471.050140817417 - 20 -1256.586620183545 - 0 -LINE - 5 -A37 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.820140817236 - 20 -1251.636620183537 - 11 -3467.820140817236 - 21 -1256.28662018356 - 0 -LINE - 5 -A38 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.820140817236 - 20 -1249.969758161813 - 11 -3471.050140817417 - 21 -1249.969758161813 - 0 -LINE - 5 -A39 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3464.586316400124 - 20 -1248.636620183537 - 11 -3464.586316400124 - 21 -1248.186620183525 - 0 -LINE - 5 -A3A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.590140816788 - 20 -1248.636620183537 - 11 -3467.590140816788 - 21 -1248.186620183525 - 0 -LINE - 5 -A3B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.590140817254 - 20 -1251.636620183537 - 11 -3467.590140817254 - 21 -1256.28662018356 - 0 -LINE - 5 -A3C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.45749947269 - 20 -1251.636620183537 - 11 -3467.45749947269 - 21 -1256.28662018356 - 0 -LINE - 5 -A3D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.241986530633 - 20 -1251.636620183537 - 11 -3467.241986530633 - 21 -1256.28662018356 - 0 -LINE - 5 -A3E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3466.910383170505 - 20 -1251.636620183537 - 11 -3466.910383170505 - 21 -1256.28662018356 - 0 -LINE - 5 -A3F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3466.611940146457 - 20 -1251.636620183537 - 11 -3466.611940146457 - 21 -1256.28662018356 - 0 -LINE - 5 -A40 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3466.247176450244 - 20 -1251.636620183537 - 11 -3466.247176450244 - 21 -1256.28662018356 - 0 -LINE - 5 -A41 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3465.817288587485 - 20 -1251.636620183537 - 11 -3465.817288587485 - 21 -1256.28662018356 - 0 -LWPOLYLINE - 5 -A42 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 0 - 43 -0 - 10 -3463.20631640012 - 20 -1256.28662018356 - 10 -3462.882670446765 - 20 -1256.286620183557 - 10 -3462.882670446765 - 20 -1256.286620183557 - 10 -3462.882670446765 - 20 -1256.586620183545 - 10 -3468.190140816849 - 20 -1256.586620183545 - 10 -3468.190140816849 - 20 -1256.586620183545 - 10 -3468.190140816849 - 20 -1256.286620183557 - 10 -3462.882670446765 - 20 -1256.286620183557 - 0 -LINE - 5 -A43 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3464.586316400011 - 20 -1256.586620183607 - 11 -3464.586316400011 - 21 -1260.786620183618 - 0 -LWPOLYLINE - 5 -A44 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3459.582670446752 - 20 -1248.186620183584 - 10 -3459.582670446752 - 20 -1260.786620183618 - 10 -3459.582670446752 - 20 -1261.98662018363 - 10 -3459.35267044677 - 20 -1261.98662018363 - 10 -3459.35267044677 - 20 -1248.186620183584 - 0 -LWPOLYLINE - 5 -A45 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3459.582670446718 - 20 -1260.786620183615 - 10 -3463.112670446513 - 20 -1260.786620183557 - 0 -LWPOLYLINE - 5 -A46 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3463.112670446746 - 20 -1250.43662018358 - 10 -3463.112670446746 - 20 -1256.286620183559 - 0 -LWPOLYLINE - 5 -A47 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3463.112670446662 - 20 -1251.486620183514 - 10 -3463.112670446662 - 20 -1248.186620183525 - 0 -LWPOLYLINE - 5 -A48 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3459.582670447184 - 20 -1251.636620183592 - 10 -3464.737670446746 - 20 -1251.636620183592 - 10 -3464.737670446746 - 20 -1251.486620183626 - 10 -3459.582670447184 - 20 -1251.486620183626 - 0 -LINE - 5 -A49 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.820140817236 - 20 -1251.48662018363 - 11 -3467.820140817236 - 21 -1251.636620183595 - 0 -LINE - 5 -A4A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.756694022715 - 20 -1251.486620183514 - 11 -3467.756694022715 - 21 -1251.636620183537 - 0 -LINE - 5 -A4B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.613932289915 - 20 -1251.486620183514 - 11 -3467.613932289915 - 21 -1251.636620183537 - 0 -LINE - 5 -A4C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.21341312028 - 20 -1251.486620183514 - 11 -3467.21341312028 - 21 -1251.636620183537 - 0 -LINE - 5 -A4D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3466.741519529406 - 20 -1251.486620183514 - 11 -3466.741519529406 - 21 -1251.636620183537 - 0 -LINE - 5 -A4E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3466.187346196767 - 20 -1251.486620183514 - 11 -3466.187346196767 - 21 -1251.636620183537 - 0 -LINE - 5 -A4F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3465.649956229874 - 20 -1251.486620183514 - 11 -3465.649956229874 - 21 -1251.636620183537 - 0 -LINE - 5 -A50 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3459.582670446718 - 20 -1255.284725128789 - 11 -3463.112670446746 - 21 -1260.043325668128 - 0 -LINE - 5 -A51 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3459.582670446752 - 20 -1255.284725128793 - 11 -3459.582670446752 - 21 -1255.13472512877 - 0 -LINE - 5 -A52 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3459.582670447184 - 20 -1255.134725128882 - 11 -3463.112670446746 - 21 -1259.237228920667 - 0 -LWPOLYLINE - 5 -A53 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3465.24477250435 - 20 -1256.586620183549 - 10 -3465.24477250435 - 20 -1258.686620183525 - 10 -3466.444772504303 - 20 -1258.686620183525 - 10 -3466.444772504303 - 20 -1256.586620183549 - 0 -LWPOLYLINE - 5 -A54 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3465.144772504373 - 20 -1256.586620183549 - 10 -3465.144772504373 - 20 -1258.78662018356 - 10 -3466.54477250428 - 20 -1258.78662018356 - 10 -3466.54477250428 - 20 -1256.586620183549 - 0 -LWPOLYLINE - 5 -A55 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3467.103228608529 - 20 -1256.586620183549 - 10 -3467.103228608529 - 20 -1258.686620183525 - 10 -3468.303228608482 - 20 -1258.686620183525 - 10 -3468.303228608482 - 20 -1256.586620183549 - 0 -LWPOLYLINE - 5 -A56 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3467.003228608435 - 20 -1256.586620183549 - 10 -3467.003228608435 - 20 -1258.78662018356 - 10 -3468.403228608459 - 20 -1258.78662018356 - 10 -3468.403228608459 - 20 -1256.586620183549 - 0 -LWPOLYLINE - 5 -A57 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3468.961684712591 - 20 -1256.586620183549 - 10 -3468.961684712591 - 20 -1258.686620183525 - 10 -3470.161684712861 - 20 -1258.686620183522 - 10 -3470.161684712861 - 20 -1256.586620183545 - 0 -LWPOLYLINE - 5 -A58 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3468.861684712614 - 20 -1256.586620183549 - 10 -3468.861684712614 - 20 -1258.78662018356 - 10 -3470.261684712637 - 20 -1258.78662018356 - 10 -3470.261684712637 - 20 -1256.586620183549 - 0 -LINE - 5 -A59 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3468.190140816849 - 20 -1256.286620183557 - 11 -3470.612173036905 - 21 -1256.286620183557 - 0 -LINE - 5 -A5A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3470.612173036905 - 20 -1256.286620183557 - 11 -3471.062173036859 - 21 -1256.286620183557 - 0 -LINE - 5 -A5B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3471.062173036859 - 20 -1256.286620183557 - 11 -3471.062173036859 - 21 -1256.586620183545 - 0 -LWPOLYLINE - 5 -A5C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3468.190140816849 - 20 -1256.586620183545 - 10 -3471.062173036859 - 20 -1256.586620183545 - 0 -LINE - 5 -A5D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3459.582670446752 - 20 -1253.347083962293 - 11 -3463.112670446746 - 21 -1258.105684500897 - 0 -LINE - 5 -A5E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3459.582670446752 - 20 -1253.197083962328 - 11 -3463.112670446746 - 21 -1257.299587754597 - 0 -LINE - 5 -A5F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3459.582670446752 - 20 -1252.000193151998 - 11 -3462.882670446765 - 21 -1256.448743230605 - 0 -LINE - 5 -A60 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3459.582670446752 - 20 -1251.850193151975 - 11 -3463.112670446662 - 21 -1255.952696944241 - 0 -LINE - 5 -A61 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3460.504927551523 - 20 -1251.636620183537 - 11 -3463.112670446662 - 21 -1255.151976202094 - 0 -LINE - 5 -A62 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3460.781487901844 - 20 -1251.636620183537 - 11 -3463.112670446662 - 21 -1254.345879455799 - 0 -LINE - 5 -A63 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3459.582670446752 - 20 -1257.978506749325 - 11 -3461.665770371246 - 21 -1260.78662018356 - 0 -LINE - 5 -A64 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3459.582670446752 - 20 -1257.828506749302 - 11 -3462.127979592453 - 21 -1260.78662018356 - 0 -LWPOLYLINE - 5 -A65 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3464.586316399835 - 20 -1256.586620183622 - 10 -3464.586316399835 - 20 -1261.986620183529 - 10 -3463.112670446746 - 20 -1261.986620183529 - 0 -LWPOLYLINE - 5 -A66 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3456.997920704456 - 20 -1246.025655220324 - 10 -3455.983326281337 - 20 -1247.471872850558 - 10 -3456.29634507679 - 20 -1247.769085132695 - 10 -3455.76420152307 - 20 -1247.800370254674 - 10 -3456.265047064433 - 20 -1247.988088233458 - 10 -3455.795512425979 - 20 -1248.926649139383 - 0 -LINE - 5 -A67 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.520140817389 - 20 -1247.569641536742 - 11 -3471.050140817417 - 21 -1247.569641536742 - 0 -LWPOLYLINE - 5 -A68 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3464.586316400011 - 20 -1251.636620183595 - 10 -3464.586316400011 - 20 -1248.186620183584 - 0 -LWPOLYLINE - 5 -A69 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3464.586316399975 - 20 -1259.886620183533 - 10 -3471.050140817417 - 20 -1259.886620183533 - 10 -3471.050140817417 - 20 -1259.886620183533 - 10 -3471.050140817417 - 20 -1259.786620183557 - 10 -3464.586316399975 - 20 -1259.786620183557 - 0 -LINE - 5 -A6A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3465.24477250435 - 20 -1258.686620183525 - 11 -3466.444772504303 - 21 -1258.686620183525 - 0 -LINE - 5 -A6B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3465.24477250435 - 20 -1257.336620183549 - 11 -3466.444772504303 - 21 -1257.336620183549 - 0 -LWPOLYLINE - 5 -A6C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3466.444772504303 - 20 -1257.336620183549 - 10 -3465.24477250435 - 20 -1257.336620183549 - 10 -3465.24477250435 - 20 -1258.686620183525 - 10 -3466.444772504303 - 20 -1258.686620183525 - 10 -3466.444772504303 - 20 -1257.336620183549 - 0 -LWPOLYLINE - 5 -A6D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3465.884772504363 - 20 -1258.606620183509 - 10 -3466.364772504345 - 20 -1258.606620183509 - 10 -3466.364772504345 - 20 -1257.416620183507 - 10 -3465.884772504363 - 20 -1257.416620183507 - 0 -LWPOLYLINE - 5 -A6E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3465.804772504289 - 20 -1257.416620183507 - 10 -3465.324772504307 - 20 -1257.416620183507 - 10 -3465.324772504307 - 20 -1258.606620183509 - 10 -3465.804772504289 - 20 -1258.606620183509 - 0 -LINE - 5 -A6F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3465.884772504363 - 20 -1257.416620183507 - 11 -3465.884772504363 - 21 -1258.606620183509 - 0 -LINE - 5 -A70 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3465.804772504289 - 20 -1257.416620183507 - 11 -3465.804772504289 - 21 -1258.606620183509 - 0 -LINE - 5 -A71 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.103228608529 - 20 -1258.686620183525 - 11 -3468.303228608482 - 21 -1258.686620183525 - 0 -LINE - 5 -A72 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.103228608529 - 20 -1257.336620183549 - 11 -3468.303228608482 - 21 -1257.336620183549 - 0 -LWPOLYLINE - 5 -A73 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3468.303228608482 - 20 -1257.336620183549 - 10 -3467.103228608529 - 20 -1257.336620183549 - 10 -3467.103228608529 - 20 -1258.686620183525 - 10 -3468.303228608482 - 20 -1258.686620183525 - 10 -3468.303228608482 - 20 -1257.336620183549 - 0 -LWPOLYLINE - 5 -A74 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3467.743228608544 - 20 -1258.606620183509 - 10 -3468.223228608525 - 20 -1258.606620183509 - 10 -3468.223228608525 - 20 -1257.416620183507 - 10 -3467.743228608544 - 20 -1257.416620183507 - 0 -LWPOLYLINE - 5 -A75 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3467.663228608468 - 20 -1257.416620183507 - 10 -3467.183228608487 - 20 -1257.416620183507 - 10 -3467.183228608487 - 20 -1258.606620183509 - 10 -3467.663228608468 - 20 -1258.606620183509 - 0 -LINE - 5 -A76 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.743228608544 - 20 -1257.416620183507 - 11 -3467.743228608544 - 21 -1258.606620183509 - 0 -LINE - 5 -A77 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.663228608468 - 20 -1257.416620183507 - 11 -3467.663228608468 - 21 -1258.606620183509 - 0 -LINE - 5 -A78 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3468.961684712591 - 20 -1258.686620183525 - 11 -3470.161684712661 - 21 -1258.686620183525 - 0 -LINE - 5 -A79 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3468.961684712591 - 20 -1257.336620183549 - 11 -3470.161684712661 - 21 -1257.336620183549 - 0 -LWPOLYLINE - 5 -A7A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3470.161684712661 - 20 -1257.336620183549 - 10 -3468.961684712591 - 20 -1257.336620183549 - 10 -3468.961684712591 - 20 -1258.686620183525 - 10 -3470.161684712661 - 20 -1258.686620183525 - 10 -3470.161684712661 - 20 -1257.336620183549 - 0 -LWPOLYLINE - 5 -A7B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3469.601684712605 - 20 -1258.606620183509 - 10 -3470.081684712588 - 20 -1258.606620183509 - 10 -3470.081684712588 - 20 -1257.416620183507 - 10 -3469.601684712605 - 20 -1257.416620183507 - 0 -LWPOLYLINE - 5 -A7C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3469.521684712648 - 20 -1257.416620183507 - 10 -3469.041684712666 - 20 -1257.416620183507 - 10 -3469.041684712666 - 20 -1258.606620183509 - 10 -3469.521684712648 - 20 -1258.606620183509 - 0 -LINE - 5 -A7D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3469.601684712605 - 20 -1257.416620183507 - 11 -3469.601684712605 - 21 -1258.606620183509 - 0 -LINE - 5 -A7E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3469.521684712648 - 20 -1257.416620183507 - 11 -3469.521684712648 - 21 -1258.606620183509 - 0 -LINE - 5 -A7F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.364366980768 - 20 -1245.78662018356 - 11 -3448.489835352786 - 21 -1245.78662018356 - 0 -HATCH - 5 -A80 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3441.284366980692 - 20 -1248.636620183537 - 11 -3442.961253593941 - 21 -1248.636620183537 - 72 - 1 - 10 -3442.961253593941 - 20 -1248.636620183537 - 11 -3442.961253593941 - 21 -1248.53662018356 - 72 - 1 - 10 -3442.961253593941 - 20 -1248.53662018356 - 11 -3441.284366980692 - 21 -1248.53662018356 - 72 - 1 - 10 -3441.284366980692 - 20 -1248.53662018356 - 11 -3441.284366980692 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A81 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3441.054366980712 - 20 -1248.636620183537 - 11 -3441.284366980692 - 21 -1248.636620183537 - 72 - 1 - 10 -3441.284366980692 - 20 -1248.636620183537 - 11 -3441.284366980692 - 21 -1248.53662018356 - 72 - 1 - 10 -3441.284366980692 - 20 -1248.53662018356 - 11 -3441.054366980712 - 21 -1248.53662018356 - 72 - 1 - 10 -3441.054366980712 - 20 -1248.53662018356 - 11 -3441.054366980712 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A82 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3438.054366980713 - 20 -1248.636620183537 - 11 -3441.054366980712 - 21 -1248.636620183537 - 72 - 1 - 10 -3441.054366980712 - 20 -1248.636620183537 - 11 -3441.054366980712 - 21 -1248.53662018356 - 72 - 1 - 10 -3441.054366980712 - 20 -1248.53662018356 - 11 -3438.054366980713 - 21 -1248.53662018356 - 72 - 1 - 10 -3438.054366980713 - 20 -1248.53662018356 - 11 -3438.054366980713 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A83 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3437.554366980712 - 20 -1248.636620183537 - 11 -3438.054366980713 - 21 -1248.636620183537 - 72 - 1 - 10 -3438.054366980713 - 20 -1248.636620183537 - 11 -3438.054366980713 - 21 -1248.53662018356 - 72 - 1 - 10 -3438.054366980713 - 20 -1248.53662018356 - 11 -3437.554366980712 - 21 -1248.53662018356 - 72 - 1 - 10 -3437.554366980712 - 20 -1248.53662018356 - 11 -3437.554366980712 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A84 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1248.53662018356 - 11 -3431.59436698075 - 21 -1248.636620183537 - 72 - 1 - 10 -3431.59436698075 - 20 -1248.636620183537 - 11 -3437.554366980829 - 21 -1248.636620183537 - 72 - 1 - 10 -3437.554366980712 - 20 -1248.636620183537 - 11 -3437.554366980712 - 21 -1248.53662018356 - 72 - 1 - 10 -3437.554366980712 - 20 -1248.53662018356 - 11 -3431.594366980635 - 21 -1248.53662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -A85 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.892101166863 - 20 -1248.636620183553 - 10 -3433.744366980717 - 20 -1248.636620183553 - 0 -LWPOLYLINE - 5 -A86 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3444.692101166709 - 20 -1256.286620183557 - 10 -3434.244366980857 - 20 -1256.286620183557 - 0 -HATCH - 5 -A87 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3435.094366968177 - 20 -1259.78662018356 - 11 -3434.864366968195 - 21 -1259.78662018356 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.78662018356 - 11 -3434.864366968195 - 21 -1259.436620183525 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.436620183525 - 11 -3435.094366968177 - 21 -1259.436620183525 - 72 - 1 - 10 -3435.094366968177 - 20 -1259.436620183525 - 11 -3435.094366968177 - 21 -1259.78662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A88 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3434.344366980749 - 20 -1259.886620183537 - 11 -3434.344366980751 - 21 -1259.789325424532 - 72 - 1 - 10 -3434.344366980751 - 20 -1259.789325424532 - 11 -3434.594366968177 - 21 -1259.789325424532 - 72 - 1 - 10 -3434.594366968177 - 20 -1259.789325424532 - 11 -3434.594366968177 - 21 -1259.886620183537 - 72 - 1 - 10 -3434.594366968177 - 20 -1259.886620183537 - 11 -3434.344366980749 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A89 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 2 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3435.094366968177 - 20 -1259.886620183537 - 11 -3434.864366968195 - 21 -1259.886620183537 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.886620183537 - 11 -3434.864366968195 - 21 -1259.789325424532 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.789325424532 - 11 -3435.094366968177 - 21 -1259.789325424532 - 72 - 1 - 10 -3435.094366968177 - 20 -1259.789325424532 - 11 -3435.094366968177 - 21 -1259.886620183537 - 97 - 0 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3437.824366980731 - 20 -1259.886620183537 - 11 -3434.864366968195 - 21 -1259.886620183537 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.886620183537 - 11 -3434.864366968195 - 21 -1259.789325424532 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.789325424532 - 11 -3437.824366980731 - 21 -1259.789325424532 - 72 - 1 - 10 -3437.824366980731 - 20 -1259.789325424532 - 11 -3437.824366980731 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A8A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3438.054366980713 - 20 -1259.886620183537 - 11 -3437.824366980731 - 21 -1259.886620183537 - 72 - 1 - 10 -3437.824366980731 - 20 -1259.886620183537 - 11 -3437.824366980731 - 21 -1259.789325424532 - 72 - 1 - 10 -3437.824366980731 - 20 -1259.789325424532 - 11 -3438.054366980713 - 21 -1259.789325424532 - 72 - 1 - 10 -3438.054366980713 - 20 -1259.789325424532 - 11 -3438.054366980713 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A8B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3441.054366980712 - 20 -1259.886620183537 - 11 -3438.054366980713 - 21 -1259.886620183537 - 72 - 1 - 10 -3438.054366980713 - 20 -1259.886620183537 - 11 -3438.054366980713 - 21 -1259.789325424532 - 72 - 1 - 10 -3438.054366980713 - 20 -1259.789325424532 - 11 -3441.054366980712 - 21 -1259.789325424532 - 72 - 1 - 10 -3441.054366980712 - 20 -1259.789325424532 - 11 -3441.054366980712 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A8C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3441.284366980692 - 20 -1259.886620183537 - 11 -3441.054366980712 - 21 -1259.886620183537 - 72 - 1 - 10 -3441.054366980712 - 20 -1259.886620183537 - 11 -3441.054366980712 - 21 -1259.789325424532 - 72 - 1 - 10 -3441.054366980712 - 20 -1259.789325424532 - 11 -3441.284366980692 - 21 -1259.789325424532 - 72 - 1 - 10 -3441.284366980692 - 20 -1259.789325424532 - 11 -3441.284366980692 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A8D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.192101166733 - 20 -1259.886620183537 - 11 -3441.284366980692 - 21 -1259.886620183537 - 72 - 1 - 10 -3441.284366980692 - 20 -1259.886620183537 - 11 -3441.284366980692 - 21 -1259.789325424532 - 72 - 1 - 10 -3441.284366980692 - 20 -1259.789325424532 - 11 -3444.192101166733 - 21 -1259.789325424532 - 72 - 1 - 10 -3444.192101166733 - 20 -1259.789325424532 - 11 -3444.192101166733 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A8E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.554366980713 - 20 -1259.886620183537 - 11 -3444.192101166733 - 21 -1259.886620183537 - 72 - 1 - 10 -3444.192101166733 - 20 -1259.886620183537 - 11 -3444.192101166733 - 21 -1259.789325424532 - 72 - 1 - 10 -3444.192101166733 - 20 -1259.789325424532 - 11 -3444.554366980713 - 21 -1259.789325424532 - 72 - 1 - 10 -3444.554366980713 - 20 -1259.789325424532 - 11 -3444.554366980713 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A8F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.784366980695 - 20 -1259.886620183537 - 11 -3444.554366980713 - 21 -1259.886620183537 - 72 - 1 - 10 -3444.554366980713 - 20 -1259.886620183537 - 11 -3444.554366980713 - 21 -1259.789325424532 - 72 - 1 - 10 -3444.554366980713 - 20 -1259.789325424532 - 11 -3444.784366980695 - 21 -1259.789325424532 - 72 - 1 - 10 -3444.784366980695 - 20 -1259.789325424532 - 11 -3444.784366980695 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A90 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3445.892101166805 - 20 -1259.886620183537 - 11 -3444.784366980695 - 21 -1259.886620183537 - 72 - 1 - 10 -3444.784366980695 - 20 -1259.886620183537 - 11 -3444.784366980695 - 21 -1259.789325424532 - 72 - 1 - 10 -3444.784366980695 - 20 -1259.789325424532 - 11 -3445.892101166805 - 21 -1259.789325424532 - 72 - 1 - 10 -3445.892101166805 - 20 -1259.789325424532 - 11 -3445.892101166805 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A91 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3447.989835352786 - 20 -1259.886620183537 - 11 -3447.922101166831 - 21 -1259.886620183537 - 72 - 1 - 10 -3447.922101166831 - 20 -1259.886620183537 - 11 -3447.922101166831 - 21 -1259.789325424532 - 72 - 1 - 10 -3447.922101166831 - 20 -1259.789325424532 - 11 -3447.989835352786 - 21 -1259.789325424532 - 72 - 1 - 10 -3447.989835352786 - 20 -1259.789325424532 - 11 -3447.989835352786 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A92 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3447.922101166831 - 20 -1259.886620183537 - 11 -3445.892101166805 - 21 -1259.886620183537 - 72 - 1 - 10 -3445.892101166805 - 20 -1259.886620183537 - 11 -3445.892101166805 - 21 -1259.789325424532 - 72 - 1 - 10 -3445.892101166805 - 20 -1259.789325424532 - 11 -3447.922101166831 - 21 -1259.789325424532 - 72 - 1 - 10 -3447.922101166831 - 20 -1259.789325424532 - 11 -3447.922101166831 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A93 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.162101166705 - 20 -1259.886620183537 - 11 -3447.989835352786 - 21 -1259.886620183537 - 72 - 1 - 10 -3447.989835352786 - 20 -1259.886620183537 - 11 -3447.989835352786 - 21 -1259.789325424532 - 72 - 1 - 10 -3447.989835352786 - 20 -1259.789325424532 - 11 -3448.162101166705 - 21 -1259.789325424532 - 72 - 1 - 10 -3448.162101166705 - 20 -1259.789325424532 - 11 -3448.162101166705 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A94 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.29210116671 - 20 -1259.886620183537 - 11 -3448.162101166705 - 21 -1259.886620183537 - 72 - 1 - 10 -3448.162101166705 - 20 -1259.886620183537 - 11 -3448.162101166705 - 21 -1259.789325424532 - 72 - 1 - 10 -3448.162101166705 - 20 -1259.789325424532 - 11 -3448.29210116671 - 21 -1259.789325424532 - 72 - 1 - 10 -3448.29210116671 - 20 -1259.789325424532 - 11 -3448.29210116671 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A95 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.489835352786 - 20 -1259.886620183537 - 11 -3448.29210116671 - 21 -1259.886620183537 - 72 - 1 - 10 -3448.29210116671 - 20 -1259.886620183537 - 11 -3448.29210116671 - 21 -1259.789325424532 - 72 - 1 - 10 -3448.29210116671 - 20 -1259.789325424532 - 11 -3448.489835352786 - 21 -1259.789325424532 - 72 - 1 - 10 -3448.489835352786 - 20 -1259.789325424532 - 11 -3448.489835352786 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A96 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.489835352786 - 20 -1259.78662018356 - 11 -3448.29210116671 - 21 -1259.78662018356 - 72 - 1 - 10 -3448.29210116671 - 20 -1259.78662018356 - 11 -3448.29210116671 - 21 -1259.436620183525 - 72 - 1 - 10 -3448.29210116671 - 20 -1259.436620183525 - 11 -3448.489835352786 - 21 -1259.436620183525 - 72 - 1 - 10 -3448.489835352786 - 20 -1259.436620183525 - 11 -3448.489835352786 - 21 -1259.78662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A97 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 2 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3435.094366968177 - 20 -1259.886620183537 - 11 -3434.864366968195 - 21 -1259.886620183537 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.886620183537 - 11 -3434.864366968195 - 21 -1259.789325424532 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.789325424532 - 11 -3435.094366968177 - 21 -1259.789325424532 - 72 - 1 - 10 -3435.094366968177 - 20 -1259.789325424532 - 11 -3435.094366968177 - 21 -1259.886620183537 - 97 - 0 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.886620183537 - 11 -3434.594366968177 - 21 -1259.886620183537 - 72 - 1 - 10 -3434.594366968177 - 20 -1259.886620183537 - 11 -3434.594366968177 - 21 -1259.789325424532 - 72 - 1 - 10 -3434.594366968177 - 20 -1259.789325424532 - 11 -3434.864366968195 - 21 -1259.789325424532 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.789325424532 - 11 -3434.864366968195 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -A98 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3448.489835352786 - 20 -1259.789325424532 - 10 -3434.344366980751 - 20 -1259.789325424532 - 0 -LWPOLYLINE - 5 -A99 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3448.489835352637 - 20 -1259.886620183537 - 10 -3434.344366980751 - 20 -1259.884787151034 - 0 -LWPOLYLINE - 5 -A9A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3438.054366980713 - 20 -1259.78662018356 - 10 -3437.554366980712 - 20 -1259.78662018356 - 0 -LWPOLYLINE - 5 -A9B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3444.592101166723 - 20 -1256.186620183522 - 10 -3434.144366980763 - 20 -1256.186620183522 - 0 -HATCH - 5 -A9C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.192101166733 - 20 -1248.636620183537 - 11 -3442.961253593941 - 21 -1248.636620183537 - 72 - 1 - 10 -3442.961253593941 - 20 -1248.636620183537 - 11 -3442.961253593941 - 21 -1248.53662018356 - 72 - 1 - 10 -3442.961253593941 - 20 -1248.53662018356 - 11 -3444.192101166733 - 21 -1248.53662018356 - 72 - 1 - 10 -3444.192101166733 - 20 -1248.53662018356 - 11 -3444.192101166733 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A9D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3445.187635226016 - 20 -1248.636620183537 - 11 -3444.554366980713 - 21 -1248.636620183537 - 72 - 1 - 10 -3444.554366980713 - 20 -1248.636620183537 - 11 -3444.554366980713 - 21 -1248.53662018356 - 72 - 1 - 10 -3444.554366980713 - 20 -1248.53662018356 - 11 -3445.192101166711 - 21 -1248.536620183537 - 72 - 1 - 10 -3445.192101166711 - 20 -1248.536620183537 - 11 -3445.187635226016 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A9E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.554366980713 - 20 -1248.636620183537 - 11 -3444.192101166733 - 21 -1248.636620183537 - 72 - 1 - 10 -3444.192101166733 - 20 -1248.636620183537 - 11 -3444.192101166733 - 21 -1248.53662018356 - 72 - 1 - 10 -3444.192101166733 - 20 -1248.53662018356 - 11 -3444.554366980713 - 21 -1248.53662018356 - 72 - 1 - 10 -3444.554366980713 - 20 -1248.53662018356 - 11 -3444.554366980713 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A9F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3438.054366980713 - 20 -1248.53662018356 - 11 -3437.824366980731 - 21 -1248.53662018356 - 72 - 1 - 10 -3437.824366980731 - 20 -1248.53662018356 - 11 -3437.824366980731 - 21 -1248.236620183514 - 72 - 1 - 10 -3437.824366980731 - 20 -1248.236620183514 - 11 -3438.054366980713 - 21 -1248.236620183514 - 72 - 1 - 10 -3438.054366980713 - 20 -1248.236620183514 - 11 -3438.054366980713 - 21 -1248.53662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -AA0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.784366980695 - 20 -1248.53662018356 - 11 -3444.554366980713 - 21 -1248.53662018356 - 72 - 1 - 10 -3444.554366980713 - 20 -1248.53662018356 - 11 -3444.554366980713 - 21 -1248.236620183514 - 72 - 1 - 10 -3444.554366980713 - 20 -1248.236620183514 - 11 -3444.784366980695 - 21 -1248.236620183514 - 72 - 1 - 10 -3444.784366980695 - 20 -1248.236620183514 - 11 -3444.784366980695 - 21 -1248.53662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -AA1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.192101166816 - 20 -1248.536620183557 - 10 -3431.294366980903 - 20 -1248.536620183557 - 0 -LINE - 5 -AA2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3442.961253594003 - 20 -1248.636620183553 - 11 -3442.961253594003 - 21 -1245.786620183576 - 0 -LINE - 5 -AA3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3442.961253593941 - 20 -1245.78662018356 - 11 -3440.757226175545 - 21 -1245.78662018356 - 0 -LINE - 5 -AA4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.364366980768 - 20 -1245.631902978352 - 11 -3431.364366980768 - 21 -1262.186620183525 - 0 -LINE - 5 -AA5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3437.824366980731 - 20 -1244.28662018356 - 11 -3437.824366980731 - 21 -1252.586686850121 - 0 -LINE - 5 -AA6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 3 -370 - 0 -100 -AcDbLine - 10 -3437.824366980731 - 20 -1252.686620183525 - 11 -3437.824366980731 - 21 -1256.186620183525 - 0 -LINE - 5 -AA7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3437.824366980731 - 20 -1256.28662018356 - 11 -3437.824366980731 - 21 -1259.886620183537 - 0 -LINE - 5 -AA8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1244.28662018356 - 11 -3438.054366980713 - 21 -1252.586691256267 - 0 -LINE - 5 -AA9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 3 -370 - 0 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1252.686620183525 - 11 -3438.054366980713 - 21 -1256.186620183525 - 0 -LINE - 5 -AAA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1256.28662018356 - 11 -3438.054366980713 - 21 -1259.886620183537 - 0 -LINE - 5 -AAB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 3 -370 - 0 -100 -AcDbLine - 10 -3441.284366980692 - 20 -1252.686620183525 - 11 -3441.284366980692 - 21 -1256.186620183525 - 0 -LINE - 5 -AAC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 3 -370 - 0 -100 -AcDbLine - 10 -3441.284366980692 - 20 -1256.28662018356 - 11 -3441.284366980692 - 21 -1259.886620183537 - 0 -LINE - 5 -AAD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 3 -370 - 0 -100 -AcDbLine - 10 -3441.054366980712 - 20 -1252.686620183525 - 11 -3441.054366980712 - 21 -1256.186620183525 - 0 -LINE - 5 -AAE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 3 -370 - 0 -100 -AcDbLine - 10 -3441.054366980712 - 20 -1256.28662018356 - 11 -3441.054366980712 - 21 -1259.886620183537 - 0 -LINE - 5 -AAF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.55436698068 - 20 -1244.286620183557 - 11 -3444.55436698068 - 21 -1248.636620183533 - 0 -LINE - 5 -AB0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.784366980695 - 20 -1244.28662018356 - 11 -3444.784366980695 - 21 -1248.636620183553 - 0 -HATCH - 5 -AB1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1247.436620183525 - 11 -3431.364366980768 - 21 -1247.436620183525 - 72 - 1 - 10 -3431.364366980768 - 20 -1247.436620183525 - 11 -3431.364366980768 - 21 -1247.336620183549 - 72 - 1 - 10 -3431.364366980768 - 20 -1247.336620183549 - 11 -3431.59436698075 - 21 -1247.336620183549 - 72 - 1 - 10 -3431.59436698075 - 20 -1247.336620183549 - 11 -3431.59436698075 - 21 -1247.436620183525 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -AB2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1247.78662018356 - 11 -3431.364366980768 - 21 -1247.78662018356 - 72 - 1 - 10 -3431.364366980768 - 20 -1247.78662018356 - 11 -3431.364366980768 - 21 -1247.436620183525 - 72 - 1 - 10 -3431.364366980768 - 20 -1247.436620183525 - 11 -3431.59436698075 - 21 -1247.436620183525 - 72 - 1 - 10 -3431.59436698075 - 20 -1247.436620183525 - 11 -3431.59436698075 - 21 -1247.78662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -AB3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3444.784366980695 - 20 -1245.78662018356 - 10 -3431.364366980768 - 20 -1245.78662018356 - 0 -LINE - 5 -AB4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3453.138227600405 - 20 -1246.986620183514 - 11 -3448.489835352786 - 21 -1248.035623844076 - 0 -LWPOLYLINE - 5 -AB5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3429.255147392662 - 20 -1245.631902978352 - 10 -3429.255147392662 - 20 -1246.386620183537 - 10 -3429.255147392662 - 20 -1246.986620183514 - 10 -3424.159135151804 - 20 -1246.986620183514 - 0 -LWPOLYLINE - 5 -AB6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3429.255147392662 - 20 -1246.986620183514 - 10 -3429.255147392662 - 20 -1248.186620183525 - 10 -3429.485147392643 - 20 -1248.186620183525 - 10 -3429.485147392643 - 20 -1245.486620183514 - 0 -LINE - 5 -AB7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3451.883573844015 - 20 -1247.269758161801 - 11 -3447.092101166756 - 21 -1245.78662018356 - 0 -LINE - 5 -AB8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.59436698075 - 20 -1248.636620183537 - 11 -3431.59436698075 - 21 -1245.78662018356 - 0 -HATCH - 5 -AB9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.364366980768 - 20 -1245.78662018356 - 11 -3431.59436698075 - 21 -1245.78662018356 - 72 - 1 - 10 -3431.59436698075 - 20 -1245.78662018356 - 11 -3431.59436698075 - 21 -1245.686620183525 - 72 - 1 - 10 -3431.59436698075 - 20 -1245.686620183525 - 11 -3431.364366980768 - 21 -1245.686620183525 - 72 - 1 - 10 -3431.364366980768 - 20 -1245.686620183525 - 11 -3431.364366980768 - 21 -1245.78662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -ABA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.364366980768 - 20 -1245.686620183525 - 11 -3431.59436698075 - 21 -1245.686620183525 - 72 - 1 - 10 -3431.59436698075 - 20 -1245.686620183525 - 11 -3431.59436698075 - 21 -1245.186620183525 - 72 - 1 - 10 -3431.59436698075 - 20 -1245.186620183525 - 11 -3431.364366980768 - 21 -1245.186620183525 - 72 - 1 - 10 -3431.364366980768 - 20 -1245.186620183525 - 11 -3431.364366980768 - 21 -1245.686620183525 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -ABB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3431.59436698075 - 20 -1245.78662018356 - 10 -3431.364366980768 - 20 -1245.78662018356 - 10 -3431.364366980768 - 20 -1245.186620183525 - 10 -3431.59436698075 - 20 -1245.186620183525 - 10 -3431.59436698075 - 20 -1245.78662018356 - 0 -HATCH - 5 -ABC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3437.824366980731 - 20 -1245.78662018356 - 11 -3438.054366980713 - 21 -1245.78662018356 - 72 - 1 - 10 -3438.054366980713 - 20 -1245.78662018356 - 11 -3438.054366980713 - 21 -1245.686620183525 - 72 - 1 - 10 -3438.054366980713 - 20 -1245.686620183525 - 11 -3437.824366980731 - 21 -1245.686620183525 - 72 - 1 - 10 -3437.824366980731 - 20 -1245.686620183525 - 11 -3437.824366980731 - 21 -1245.78662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -ABD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3437.824366980731 - 20 -1245.686620183525 - 11 -3438.054366980713 - 21 -1245.686620183525 - 72 - 1 - 10 -3438.054366980713 - 20 -1245.686620183525 - 11 -3438.054366980713 - 21 -1245.186620183525 - 72 - 1 - 10 -3438.054366980713 - 20 -1245.186620183525 - 11 -3437.824366980731 - 21 -1245.186620183525 - 72 - 1 - 10 -3437.824366980731 - 20 -1245.186620183525 - 11 -3437.824366980731 - 21 -1245.686620183525 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -ABE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3438.054366980772 - 20 -1245.786620183576 - 10 -3437.824366980791 - 20 -1245.786620183576 - 10 -3437.824366980731 - 20 -1245.186620183525 - 10 -3438.054366980713 - 20 -1245.186620183525 - 10 -3438.054366980713 - 20 -1245.78662018356 - 0 -HATCH - 5 -ABF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3441.054366980712 - 20 -1245.78662018356 - 11 -3441.284366980692 - 21 -1245.78662018356 - 72 - 1 - 10 -3441.284366980692 - 20 -1245.78662018356 - 11 -3441.284366980692 - 21 -1245.686620183525 - 72 - 1 - 10 -3441.284366980692 - 20 -1245.686620183525 - 11 -3441.054366980712 - 21 -1245.686620183525 - 72 - 1 - 10 -3441.054366980712 - 20 -1245.686620183525 - 11 -3441.054366980712 - 21 -1245.78662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -AC0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3441.054366980712 - 20 -1245.686620183525 - 11 -3441.284366980692 - 21 -1245.686620183525 - 72 - 1 - 10 -3441.284366980692 - 20 -1245.686620183525 - 11 -3441.284366980692 - 21 -1245.186620183525 - 72 - 1 - 10 -3441.284366980692 - 20 -1245.186620183525 - 11 -3441.054366980712 - 21 -1245.186620183525 - 72 - 1 - 10 -3441.054366980712 - 20 -1245.186620183525 - 11 -3441.054366980712 - 21 -1245.686620183525 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -AC1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3441.284366980692 - 20 -1245.78662018356 - 10 -3441.054366980712 - 20 -1245.78662018356 - 10 -3441.054366980712 - 20 -1245.186620183525 - 10 -3441.284366980692 - 20 -1245.186620183525 - 10 -3441.284366980692 - 20 -1245.78662018356 - 0 -HATCH - 5 -AC2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.554366980713 - 20 -1245.78662018356 - 11 -3444.784366980695 - 21 -1245.78662018356 - 72 - 1 - 10 -3444.784366980695 - 20 -1245.78662018356 - 11 -3444.784366980695 - 21 -1245.686620183525 - 72 - 1 - 10 -3444.784366980695 - 20 -1245.686620183525 - 11 -3444.554366980713 - 21 -1245.686620183525 - 72 - 1 - 10 -3444.554366980713 - 20 -1245.686620183525 - 11 -3444.554366980713 - 21 -1245.78662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -AC3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.554366980713 - 20 -1245.787767908768 - 11 -3444.784366980695 - 21 -1245.787767908768 - 72 - 1 - 10 -3444.784366980695 - 20 -1245.787767908768 - 11 -3444.784366980695 - 21 -1245.287767908768 - 72 - 1 - 10 -3444.784366980695 - 20 -1245.287767908768 - 11 -3444.554366980713 - 21 -1245.287767908768 - 72 - 1 - 10 -3444.554366980713 - 20 -1245.287767908768 - 11 -3444.554366980713 - 21 -1245.787767908768 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -AC4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3444.784366980695 - 20 -1245.78662018356 - 10 -3444.554366980713 - 20 -1245.78662018356 - 10 -3444.554366980713 - 20 -1245.186620183525 - 10 -3444.784366980695 - 20 -1245.186620183525 - 10 -3444.784366980695 - 20 -1245.78662018356 - 0 -DIMENSION - 5 -AC5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D72 - 10 -3441.054366980712 - 20 -1245.868946037968 - 30 -0 - 11 -3440.703357607965 - 21 -1245.996469469835 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3441.284366980692 - 23 -1246.12440066169 - 33 -0 - 14 -3441.054366980712 - 24 -1246.12440066169 - 34 -0 - 50 -180 -100 -AcDbRotatedDimension - 0 -HATCH - 5 -AC6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3441.054366980712 - 20 -1248.53662018356 - 11 -3441.284366980692 - 21 -1248.53662018356 - 72 - 1 - 10 -3441.284366980692 - 20 -1248.53662018356 - 11 -3441.284366980692 - 21 -1248.436620183525 - 72 - 1 - 10 -3441.284366980692 - 20 -1248.436620183525 - 11 -3441.054366980712 - 21 -1248.436620183525 - 72 - 1 - 10 -3441.054366980712 - 20 -1248.436620183525 - 11 -3441.054366980712 - 21 -1248.53662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -AC7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3437.824366980731 - 20 -1248.53662018356 - 11 -3438.054366980713 - 21 -1248.53662018356 - 72 - 1 - 10 -3438.054366980713 - 20 -1248.53662018356 - 11 -3438.054366980713 - 21 -1248.436620183525 - 72 - 1 - 10 -3438.054366980713 - 20 -1248.436620183525 - 11 -3437.824366980731 - 21 -1248.436620183525 - 72 - 1 - 10 -3437.824366980731 - 20 -1248.436620183525 - 11 -3437.824366980731 - 21 -1248.53662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -AC8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3431.364366980768 - 20 -1245.78662018356 - 10 -3431.364366980736 - 20 -1245.786620183557 - 10 -3430.856520395027 - 20 -1245.631902978348 - 0 -LINE - 5 -AC9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.364366980768 - 20 -1245.631902978352 - 11 -3431.364366980768 - 21 -1262.186620183525 - 0 -HATCH - 5 -ACA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 5 - 72 - 1 - 10 -3431.865465748098 - 20 -1250.572620183552 - 11 -3431.595465748081 - 21 -1250.572620183552 - 72 - 1 - 10 -3431.595465748081 - 20 -1250.572620183552 - 11 -3431.595465748081 - 21 -1250.522620183563 - 72 - 1 - 10 -3431.595465748081 - 20 -1250.522620183563 - 11 -3431.595465748081 - 21 -1250.472620183575 - 72 - 1 - 10 -3431.595465748081 - 20 -1250.472620183575 - 11 -3431.865465748098 - 21 -1250.472620183575 - 72 - 1 - 10 -3431.865465748098 - 20 -1250.472620183575 - 11 -3431.865465748098 - 21 -1250.572620183552 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LINE - 5 -ACB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.59436698075 - 20 -1245.631902978352 - 11 -3431.59436698075 - 21 -1262.186620183525 - 0 -LINE - 5 -ACC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1245.534608219346 - 11 -3435.094366968177 - 21 -1252.586634551295 - 0 -LINE - 5 -ACD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1252.686620183525 - 11 -3435.094366968177 - 21 -1256.186620183525 - 0 -LINE - 5 -ACE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1256.28662018356 - 11 -3435.094366968177 - 21 -1259.789325424532 - 0 -LINE - 5 -ACF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1244.28662018356 - 11 -3438.054366980713 - 21 -1252.586691256267 - 0 -LINE - 5 -AD0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1252.686620183525 - 11 -3438.054366980713 - 21 -1256.186620183525 - 0 -LINE - 5 -AD1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1256.28662018356 - 11 -3438.054366980713 - 21 -1259.886620183537 - 0 -LINE - 5 -AD2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3437.824366980731 - 20 -1244.28662018356 - 11 -3437.824366980731 - 21 -1252.586686850121 - 0 -LINE - 5 -AD3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3437.824366980731 - 20 -1252.686620183525 - 11 -3437.824366980731 - 21 -1256.186620183525 - 0 -LINE - 5 -AD4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3437.824366980731 - 20 -1256.28662018356 - 11 -3437.824366980731 - 21 -1259.886620183537 - 0 -LINE - 5 -AD5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3441.054366980712 - 20 -1252.686620183525 - 11 -3441.054366980712 - 21 -1256.186620183525 - 0 -LINE - 5 -AD6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3441.054366980712 - 20 -1256.28662018356 - 11 -3441.054366980712 - 21 -1259.886620183537 - 0 -LINE - 5 -AD7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3441.284366980692 - 20 -1252.686620183525 - 11 -3441.284366980692 - 21 -1256.186620183525 - 0 -LINE - 5 -AD8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3441.284366980692 - 20 -1256.28662018356 - 11 -3441.284366980692 - 21 -1259.886620183537 - 0 -LINE - 5 -AD9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.489835352637 - 20 -1245.631902978348 - 11 -3448.489835352637 - 21 -1261.231902978325 - 0 -LINE - 5 -ADA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3433.744366980717 - 20 -1248.636620183553 - 11 -3438.054366980772 - 21 -1248.636620183553 - 0 -HATCH - 5 -ADB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.392101166688 - 20 -1247.586620183549 - 11 -3448.29210116671 - 21 -1247.586620183549 - 72 - 1 - 10 -3448.29210116671 - 20 -1247.586620183549 - 11 -3448.29210116671 - 21 -1247.28662018356 - 72 - 1 - 10 -3448.29210116671 - 20 -1247.28662018356 - 11 -3448.392101166688 - 21 -1247.28662018356 - 72 - 1 - 10 -3448.392101166688 - 20 -1247.28662018356 - 11 -3448.392101166688 - 21 -1247.586620183549 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -ADC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.489835352786 - 20 -1247.586620183549 - 11 -3448.392101166688 - 21 -1247.586620183549 - 72 - 1 - 10 -3448.392101166688 - 20 -1247.586620183549 - 11 -3448.392101166688 - 21 -1247.28662018356 - 72 - 1 - 10 -3448.392101166688 - 20 -1247.28662018356 - 11 -3448.489835352786 - 21 -1247.28662018356 - 72 - 1 - 10 -3448.489835352786 - 20 -1247.28662018356 - 11 -3448.489835352786 - 21 -1247.586620183549 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -ADD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.489835352786 - 20 -1247.28662018356 - 11 -3448.392101166688 - 21 -1247.28662018356 - 72 - 1 - 10 -3448.392101166688 - 20 -1247.28662018356 - 11 -3448.392101166688 - 21 -1247.186620183525 - 72 - 1 - 10 -3448.392101166688 - 20 -1247.186620183525 - 11 -3448.489835352786 - 21 -1247.186620183525 - 72 - 1 - 10 -3448.489835352786 - 20 -1247.186620183525 - 11 -3448.489835352786 - 21 -1247.28662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -ADE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.392101166688 - 20 -1247.28662018356 - 11 -3448.29210116671 - 21 -1247.28662018356 - 72 - 1 - 10 -3448.29210116671 - 20 -1247.28662018356 - 11 -3448.29210116671 - 21 -1247.186620183525 - 72 - 1 - 10 -3448.29210116671 - 20 -1247.186620183525 - 11 -3448.392101166688 - 21 -1247.186620183525 - 72 - 1 - 10 -3448.392101166688 - 20 -1247.186620183525 - 11 -3448.392101166688 - 21 -1247.28662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -ADF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.29210116671 - 20 -1247.28662018356 - 11 -3448.162101166705 - 21 -1247.28662018356 - 72 - 1 - 10 -3448.162101166705 - 20 -1247.28662018356 - 11 -3448.162101166705 - 21 -1247.186620183525 - 72 - 1 - 10 -3448.162101166705 - 20 -1247.186620183525 - 11 -3448.29210116671 - 21 -1247.186620183525 - 72 - 1 - 10 -3448.29210116671 - 20 -1247.186620183525 - 11 -3448.29210116671 - 21 -1247.28662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -AE0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.162101166705 - 20 -1247.28662018356 - 11 -3447.989835352786 - 21 -1247.28662018356 - 72 - 1 - 10 -3447.989835352786 - 20 -1247.28662018356 - 11 -3447.989835352786 - 21 -1247.186620183525 - 72 - 1 - 10 -3447.989835352786 - 20 -1247.186620183525 - 11 -3448.162101166705 - 21 -1247.186620183525 - 72 - 1 - 10 -3448.162101166705 - 20 -1247.186620183525 - 11 -3448.162101166705 - 21 -1247.28662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LINE - 5 -AE1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1259.789325424532 - 11 -3435.094366968177 - 21 -1256.28662018356 - 0 -LINE - 5 -AE2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1256.186620183525 - 11 -3435.094366968177 - 21 -1252.686620183525 - 0 -LINE - 5 -AE3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1252.586634551295 - 11 -3435.094366968177 - 21 -1245.534608219346 - 0 -LINE - 5 -AE4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3437.824366980731 - 20 -1259.886620183537 - 11 -3437.824366980731 - 21 -1256.28662018356 - 0 -LINE - 5 -AE5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3437.824366980731 - 20 -1256.186620183525 - 11 -3437.824366980731 - 21 -1252.686620183525 - 0 -LINE - 5 -AE6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3437.824366980731 - 20 -1252.586686850121 - 11 -3437.824366980731 - 21 -1244.28662018356 - 0 -LINE - 5 -AE7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1259.886620183537 - 11 -3438.054366980713 - 21 -1256.28662018356 - 0 -LINE - 5 -AE8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1256.186620183525 - 11 -3438.054366980713 - 21 -1252.686620183525 - 0 -LINE - 5 -AE9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1252.586691256267 - 11 -3438.054366980713 - 21 -1244.28662018356 - 0 -LINE - 5 -AEA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3441.054366980712 - 20 -1259.886620183537 - 11 -3441.054366980712 - 21 -1256.28662018356 - 0 -LINE - 5 -AEB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3441.054366980712 - 20 -1256.186620183525 - 11 -3441.054366980712 - 21 -1252.686620183525 - 0 -LINE - 5 -AEC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3441.284366980692 - 20 -1259.886620183537 - 11 -3441.284366980692 - 21 -1256.28662018356 - 0 -LINE - 5 -AED -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3441.284366980692 - 20 -1256.186620183525 - 11 -3441.284366980692 - 21 -1252.686620183525 - 0 -LINE - 5 -AEE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.192101166733 - 20 -1249.28662018356 - 11 -3444.192101166733 - 21 -1245.78662018356 - 0 -LINE - 5 -AEF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.489835352637 - 20 -1261.231902978325 - 11 -3448.489835352637 - 21 -1245.631902978348 - 0 -LINE - 5 -AF0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.29210116671 - 20 -1259.886620183537 - 11 -3448.29210116671 - 21 -1245.78662018356 - 0 -LINE - 5 -AF1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.48983535287 - 20 -1261.231902978325 - 11 -3448.48983535287 - 21 -1245.786620183557 - 0 -LWPOLYLINE - 5 -AF2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3447.092101166724 - 20 -1246.961620183545 - 10 -3447.092101166724 - 20 -1247.711620183545 - 0 -LWPOLYLINE - 5 -AF3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3457.965393430237 - 20 -1246.986620183514 - 10 -3453.888227600405 - 20 -1246.986620183514 - 10 -3453.888227600405 - 20 -1246.086620183549 - 10 -3453.138227600405 - 20 -1246.086620183549 - 10 -3453.138227600405 - 20 -1246.986620183514 - 10 -3453.138227600405 - 20 -1246.986620183514 - 0 -LINE - 5 -AF4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3429.485147392643 - 20 -1245.631902978352 - 11 -3450.19467215965 - 21 -1245.631902978352 - 0 -HATCH - 5 -AF5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 5 - 72 - 1 - 10 -3429.485147392643 - 20 -1247.186620183525 - 11 -3429.255147392662 - 21 -1247.186620183525 - 72 - 1 - 10 -3429.255147392662 - 20 -1247.186620183525 - 11 -3429.255147392662 - 21 -1246.986620183514 - 72 - 1 - 10 -3429.255147392662 - 20 -1246.986620183514 - 11 -3429.260147392666 - 21 -1245.631902978352 - 72 - 1 - 10 -3429.260147392666 - 20 -1245.631902978352 - 11 -3429.485147392643 - 21 -1245.631902978352 - 72 - 1 - 10 -3429.485147392643 - 20 -1245.631902978352 - 11 -3429.485147392643 - 21 -1247.186620183525 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -AF6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3429.485147392643 - 20 -1245.631902978352 - 11 -3429.03514739269 - 21 -1245.631902978352 - 72 - 1 - 10 -3429.03514739269 - 20 -1245.631902978352 - 11 -3429.03514739269 - 21 -1245.031902978375 - 72 - 1 - 10 -3429.03514739269 - 20 -1245.031902978375 - 11 -3429.485147392643 - 21 -1245.031902978375 - 72 - 1 - 10 -3429.485147392643 - 20 -1245.031902978375 - 11 -3429.485147392643 - 21 -1245.631902978352 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -AF7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3429.485147392643 - 20 -1245.631902978352 - 10 -3429.03514739269 - 20 -1245.631902978352 - 10 -3429.03514739269 - 20 -1245.031902978375 - 10 -3429.485147392643 - 20 -1245.031902978375 - 10 -3429.485147392643 - 20 -1245.631902978352 - 0 -LWPOLYLINE - 5 -AF8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3448.29210116671 - 20 -1247.28662018356 - 10 -3448.489835352786 - 20 -1247.28662018356 - 0 -LWPOLYLINE - 5 -AF9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3445.892101166805 - 20 -1259.789325424532 - 10 -3445.892101166805 - 20 -1263.248947075572 - 10 -3447.922101166831 - 20 -1263.248947075572 - 10 -3447.922101166831 - 20 -1259.789325424532 - 0 -LINE - 5 -AFA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1262.189325424497 - 11 -3435.094366968177 - 21 -1256.28662018356 - 0 -LINE - 5 -AFB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1256.186620183525 - 11 -3435.094366968177 - 21 -1252.686620183525 - 0 -LINE - 5 -AFC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1252.586634551295 - 11 -3435.094366968177 - 21 -1245.534608219346 - 0 -LINE - 5 -AFD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3434.594366968177 - 20 -1262.28662018356 - 11 -3434.594366968177 - 21 -1256.28662018356 - 0 -LINE - 5 -AFE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3434.594366968177 - 20 -1256.186620183525 - 11 -3434.594366968177 - 21 -1252.686620183525 - 0 -LINE - 5 -AFF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3434.594366968177 - 20 -1252.586624972759 - 11 -3434.594366968177 - 21 -1245.631902978352 - 0 -LINE - 5 -B00 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1259.689325424497 - 11 -3435.094366968177 - 21 -1262.189325424497 - 0 -HATCH - 5 -B01 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3434.864366968195 - 20 -1262.28662018356 - 11 -3431.59436698075 - 21 -1262.28662018356 - 72 - 1 - 10 -3431.59436698075 - 20 -1262.28662018356 - 11 -3431.59436698075 - 21 -1262.189325424497 - 72 - 1 - 10 -3431.59436698075 - 20 -1262.189325424497 - 11 -3434.864366968195 - 21 -1262.189325424497 - 72 - 1 - 10 -3434.864366968195 - 20 -1262.189325424497 - 11 -3434.864366968195 - 21 -1262.28662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -0.01 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -LINE - 5 -B02 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1262.189325424497 - 11 -3431.364366980768 - 21 -1262.189325424497 - 0 -LINE - 5 -B03 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbLine - 10 -3431.364366980768 - 20 -1262.28662018356 - 11 -3435.094366968177 - 21 -1262.28662018356 - 0 -HATCH - 5 -B04 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3435.094366968177 - 20 -1262.28662018356 - 11 -3434.864366968195 - 21 -1262.28662018356 - 72 - 1 - 10 -3434.864366968195 - 20 -1262.28662018356 - 11 -3434.864366968195 - 21 -1262.186620183525 - 72 - 1 - 10 -3434.864366968195 - 20 -1262.186620183525 - 11 -3435.094366968177 - 21 -1262.186620183525 - 72 - 1 - 10 -3435.094366968177 - 20 -1262.186620183525 - 11 -3435.094366968177 - 21 -1262.28662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B05 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3435.694366968153 - 20 -1262.086620183549 - 11 -3435.094366968177 - 21 -1262.086620183549 - 72 - 1 - 10 -3435.094366968177 - 20 -1262.086620183549 - 11 -3435.094366968177 - 21 -1261.986620183514 - 72 - 1 - 10 -3435.094366968177 - 20 -1261.986620183514 - 11 -3435.694366968153 - 21 -1261.986620183514 - 72 - 1 - 10 -3435.694366968153 - 20 -1261.986620183514 - 11 -3435.694366968153 - 21 -1262.086620183549 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B06 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3435.094366968177 - 20 -1262.186620183525 - 11 -3434.864366968195 - 21 -1262.186620183525 - 72 - 1 - 10 -3434.864366968195 - 20 -1262.186620183525 - 11 -3434.864366968195 - 21 -1261.986620183514 - 72 - 1 - 10 -3434.864366968195 - 20 -1261.986620183514 - 11 -3435.094366968177 - 21 -1261.986620183514 - 72 - 1 - 10 -3435.094366968177 - 20 -1261.986620183514 - 11 -3435.094366968177 - 21 -1262.186620183525 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B07 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3435.094366968177 - 20 -1259.789325424532 - 10 -3435.094366968177 - 20 -1262.189325424497 - 10 -3434.864366968195 - 20 -1262.189325424497 - 10 -3434.864366968195 - 20 -1259.789325424532 - 0 -LWPOLYLINE - 5 -B08 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3434.864366968195 - 20 -1261.986620183514 - 10 -3435.094366968177 - 20 -1261.986620183514 - 10 -3435.694366968153 - 20 -1261.986620183514 - 10 -3435.694366968153 - 20 -1262.086620183549 - 10 -3435.094366968177 - 20 -1262.086620183549 - 0 -HATCH - 5 -B09 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1247.836620183549 - 11 -3431.364366980768 - 21 -1247.836620183549 - 72 - 1 - 10 -3431.364366980768 - 20 -1247.836620183549 - 11 -3431.364366980768 - 21 -1247.78662018356 - 72 - 1 - 10 -3431.364366980768 - 20 -1247.78662018356 - 11 -3431.59436698075 - 21 -1247.78662018356 - 72 - 1 - 10 -3431.59436698075 - 20 -1247.78662018356 - 11 -3431.59436698075 - 21 -1247.836620183549 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B0A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.364366980768 - 20 -1247.78662018356 - 11 -3430.764366980675 - 21 -1247.78662018356 - 72 - 1 - 10 -3430.764366980675 - 20 -1247.78662018356 - 11 -3430.764366980675 - 21 -1247.686620183525 - 72 - 1 - 10 -3430.764366980675 - 20 -1247.686620183525 - 11 -3431.364366980768 - 21 -1247.686620183525 - 72 - 1 - 10 -3431.364366980768 - 20 -1247.686620183525 - 11 -3431.364366980768 - 21 -1247.78662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B0B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980768 - 20 -1247.336620183549 - 10 -3431.364366980768 - 20 -1247.78662018356 - 10 -3431.59436698075 - 20 -1247.78662018356 - 10 -3431.59436698075 - 20 -1247.336620183549 - 0 -LWPOLYLINE - 5 -B0C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980768 - 20 -1247.78662018356 - 10 -3430.764366980675 - 20 -1247.78662018356 - 10 -3430.764366980675 - 20 -1247.686620183525 - 10 -3431.364366980768 - 20 -1247.686620183525 - 0 -DIMENSION - 5 -B0D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D73 - 10 -3431.018724545987 - 20 -1245.631902978352 - 30 -0 - 11 -3430.89120111412 - 21 -1246.709261580955 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3430.764366980675 - 23 -1247.78662018356 - 33 -0 - 14 -3430.764366980675 - 24 -1245.631902978352 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -LWPOLYLINE - 5 -B0E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980768 - 20 -1247.78662018356 - 10 -3431.364366980768 - 20 -1247.836620183549 - 10 -3431.59436698075 - 20 -1247.836620183549 - 10 -3431.59436698075 - 20 -1247.78662018356 - 0 -LINE - 5 -B0F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3434.594366968177 - 20 -1248.636620183537 - 11 -3434.594366968177 - 21 -1248.236620183514 - 0 -LINE - 5 -B10 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.594366980717 - 20 -1248.23662018351 - 11 -3448.48983535287 - 21 -1248.23662018351 - 0 -LWPOLYLINE - 5 -B11 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3444.392101166803 - 20 -1245.78662018356 - 10 -3444.292101166826 - 20 -1245.78662018356 - 10 -3444.292101166826 - 20 -1245.584312605966 - 10 -3444.554366980713 - 20 -1245.584312605966 - 0 -LWPOLYLINE - 5 -B12 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3448.29210116671 - 20 -1247.186620183525 - 10 -3448.29210116671 - 20 -1247.586620183549 - 10 -3448.489835352786 - 20 -1247.586620183549 - 10 -3448.489835352786 - 20 -1247.186620183525 - 0 -LINE - 5 -B13 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.29210116671 - 20 -1248.636620183537 - 11 -3431.59436698075 - 21 -1248.636620183537 - 0 -LWPOLYLINE - 5 -B14 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3438.054366980713 - 20 -1248.236620183514 - 10 -3437.824366980731 - 20 -1248.236620183514 - 10 -3437.824366980731 - 20 -1248.636620183537 - 10 -3438.054366980713 - 20 -1248.636620183537 - 10 -3438.054366980713 - 20 -1248.236620183514 - 0 -HATCH - 5 -B15 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3434.594366968177 - 20 -1248.636620183537 - 11 -3435.094366968177 - 21 -1248.636620183537 - 72 - 1 - 10 -3435.094366968177 - 20 -1248.636620183537 - 11 -3435.094366968177 - 21 -1248.53662018356 - 72 - 1 - 10 -3435.094366968177 - 20 -1248.53662018356 - 11 -3434.594366968177 - 21 -1248.53662018356 - 72 - 1 - 10 -3434.594366968177 - 20 -1248.53662018356 - 11 -3434.594366968177 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B16 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3435.094366968177 - 20 -1248.53662018356 - 11 -3434.864366968195 - 21 -1248.53662018356 - 72 - 1 - 10 -3434.864366968195 - 20 -1248.53662018356 - 11 -3434.864366968195 - 21 -1248.236620183514 - 72 - 1 - 10 -3434.864366968195 - 20 -1248.236620183514 - 11 -3435.094366968177 - 21 -1248.236620183514 - 72 - 1 - 10 -3435.094366968177 - 20 -1248.236620183514 - 11 -3435.094366968177 - 21 -1248.53662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B17 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3434.864366968195 - 20 -1248.53662018356 - 11 -3435.094366968177 - 21 -1248.53662018356 - 72 - 1 - 10 -3435.094366968177 - 20 -1248.53662018356 - 11 -3435.094366968177 - 21 -1248.436620183525 - 72 - 1 - 10 -3435.094366968177 - 20 -1248.436620183525 - 11 -3434.864366968195 - 21 -1248.436620183525 - 72 - 1 - 10 -3434.864366968195 - 20 -1248.436620183525 - 11 -3434.864366968195 - 21 -1248.53662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B18 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3435.094366968177 - 20 -1248.236620183514 - 10 -3434.864366968195 - 20 -1248.236620183514 - 10 -3434.864366968195 - 20 -1248.636620183537 - 10 -3435.094366968177 - 20 -1248.636620183537 - 10 -3435.094366968177 - 20 -1248.236620183514 - 0 -HATCH - 5 -B19 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3435.094366968177 - 20 -1245.686620183525 - 11 -3434.864366968195 - 21 -1245.686620183525 - 72 - 1 - 10 -3434.864366968195 - 20 -1245.686620183525 - 11 -3434.864366968195 - 21 -1245.386620183537 - 72 - 1 - 10 -3434.864366968195 - 20 -1245.386620183537 - 11 -3435.094366968177 - 21 -1245.386620183537 - 72 - 1 - 10 -3435.094366968177 - 20 -1245.386620183537 - 11 -3435.094366968177 - 21 -1245.686620183525 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B1A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3434.864366968195 - 20 -1245.686620183525 - 11 -3435.094366968177 - 21 -1245.686620183525 - 72 - 1 - 10 -3435.094366968177 - 20 -1245.686620183525 - 11 -3435.094366968177 - 21 -1245.586620183549 - 72 - 1 - 10 -3435.094366968177 - 20 -1245.586620183549 - 11 -3434.864366968195 - 21 -1245.586620183549 - 72 - 1 - 10 -3434.864366968195 - 20 -1245.586620183549 - 11 -3434.864366968195 - 21 -1245.686620183525 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B1B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3435.094366968177 - 20 -1245.386620183537 - 10 -3434.864366968195 - 20 -1245.386620183537 - 10 -3434.864366968195 - 20 -1245.78662018356 - 10 -3435.094366968177 - 20 -1245.78662018356 - 10 -3435.094366968177 - 20 -1245.386620183537 - 0 -HATCH - 5 -B1C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1248.636620183537 - 11 -3431.364366980768 - 21 -1248.636620183537 - 72 - 1 - 10 -3431.364366980768 - 20 -1248.636620183537 - 11 -3431.364366980768 - 21 -1248.224683506243 - 72 - 1 - 10 -3431.364366980768 - 20 -1248.224683506243 - 11 -3431.59436698075 - 21 -1248.224683506243 - 72 - 1 - 10 -3431.59436698075 - 20 -1248.224683506243 - 11 -3431.59436698075 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B1D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3431.59436698075 - 20 -1248.636620183537 - 10 -3431.364366980768 - 20 -1248.636620183537 - 10 -3431.364366980768 - 20 -1248.224683506243 - 10 -3431.59436698075 - 20 -1248.224683506243 - 10 -3431.59436698075 - 20 -1248.636620183537 - 0 -HATCH - 5 -B1E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.489835352786 - 20 -1248.636620183537 - 11 -3448.29210116671 - 21 -1248.636620183537 - 72 - 1 - 10 -3448.29210116671 - 20 -1248.636620183537 - 11 -3448.29210116671 - 21 -1248.236620183514 - 72 - 1 - 10 -3448.29210116671 - 20 -1248.236620183514 - 11 -3448.489835352786 - 21 -1248.236620183514 - 72 - 1 - 10 -3448.489835352786 - 20 -1248.236620183514 - 11 -3448.489835352786 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B1F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3448.29210116671 - 20 -1248.636620183537 - 10 -3448.489835352786 - 20 -1248.636620183537 - 10 -3448.489835352786 - 20 -1248.236620183514 - 10 -3448.29210116671 - 20 -1248.236620183514 - 10 -3448.29210116671 - 20 -1248.636620183537 - 0 -HATCH - 5 -B20 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.594366980749 - 20 -1250.172620183587 - 11 -3431.364366980766 - 21 -1250.172620183587 - 72 - 1 - 10 -3431.364366980766 - 20 -1250.172620183587 - 11 -3431.364366980766 - 21 -1250.072620183552 - 72 - 1 - 10 -3431.364366980766 - 20 -1250.072620183552 - 11 -3431.594366980749 - 21 -1250.072620183552 - 72 - 1 - 10 -3431.594366980749 - 20 -1250.072620183552 - 11 -3431.594366980749 - 21 -1250.172620183587 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B21 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.594366980749 - 20 -1250.522620183563 - 11 -3431.364366980766 - 21 -1250.522620183563 - 72 - 1 - 10 -3431.364366980766 - 20 -1250.522620183563 - 11 -3431.364366980766 - 21 -1250.172620183587 - 72 - 1 - 10 -3431.364366980766 - 20 -1250.172620183587 - 11 -3431.594366980749 - 21 -1250.172620183587 - 72 - 1 - 10 -3431.594366980749 - 20 -1250.172620183587 - 11 -3431.594366980749 - 21 -1250.522620183563 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B22 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.594366980749 - 20 -1250.572620183552 - 11 -3431.364366980766 - 21 -1250.572620183552 - 72 - 1 - 10 -3431.364366980766 - 20 -1250.572620183552 - 11 -3431.364366980766 - 21 -1250.522620183563 - 72 - 1 - 10 -3431.364366980766 - 20 -1250.522620183563 - 11 -3431.594366980749 - 21 -1250.522620183563 - 72 - 1 - 10 -3431.594366980749 - 20 -1250.522620183563 - 11 -3431.594366980749 - 21 -1250.572620183552 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B23 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.364366980768 - 20 -1250.611720183518 - 11 -3430.764366980675 - 21 -1250.611720183518 - 72 - 1 - 10 -3430.764366980675 - 20 -1250.611720183518 - 11 -3430.764366980675 - 21 -1250.511720183542 - 72 - 1 - 10 -3430.764366980675 - 20 -1250.511720183542 - 11 -3431.364366980768 - 21 -1250.511720183542 - 72 - 1 - 10 -3431.364366980768 - 20 -1250.511720183542 - 11 -3431.364366980768 - 21 -1250.611720183518 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B24 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980736 - 20 -1250.614136013726 - 10 -3430.764366980643 - 20 -1250.614136013726 - 10 -3430.764366980643 - 20 -1250.514136013749 - 10 -3431.364366980736 - 20 -1250.514136013749 - 0 -HATCH - 5 -B25 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1254.140620183486 - 11 -3431.364366980768 - 21 -1254.140620183486 - 72 - 1 - 10 -3431.364366980768 - 20 -1254.140620183486 - 11 -3431.364366980768 - 21 -1254.04062018351 - 72 - 1 - 10 -3431.364366980768 - 20 -1254.04062018351 - 11 -3431.59436698075 - 21 -1254.04062018351 - 72 - 1 - 10 -3431.59436698075 - 20 -1254.04062018351 - 11 -3431.59436698075 - 21 -1254.140620183486 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B26 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1254.490620183463 - 11 -3431.364366980768 - 21 -1254.490620183463 - 72 - 1 - 10 -3431.364366980768 - 20 -1254.490620183463 - 11 -3431.364366980768 - 21 -1254.140620183486 - 72 - 1 - 10 -3431.364366980768 - 20 -1254.140620183486 - 11 -3431.59436698075 - 21 -1254.140620183486 - 72 - 1 - 10 -3431.59436698075 - 20 -1254.140620183486 - 11 -3431.59436698075 - 21 -1254.490620183463 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B27 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.364366980768 - 20 -1254.771631514657 - 11 -3430.764366980675 - 21 -1254.771631514657 - 72 - 1 - 10 -3430.764366980675 - 20 -1254.771631514657 - 11 -3430.764366980675 - 21 -1254.67163151468 - 72 - 1 - 10 -3430.764366980675 - 20 -1254.67163151468 - 11 -3431.364366980768 - 21 -1254.67163151468 - 72 - 1 - 10 -3431.364366980768 - 20 -1254.67163151468 - 11 -3431.364366980768 - 21 -1254.771631514657 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B28 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980736 - 20 -1254.770708683412 - 10 -3430.764366980643 - 20 -1254.770708683412 - 10 -3430.764366980643 - 20 -1254.670708683494 - 10 -3431.364366980736 - 20 -1254.670708683494 - 0 -HATCH - 5 -B29 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1258.020020183528 - 11 -3431.364366980768 - 21 -1258.020020183528 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.020020183528 - 11 -3431.364366980768 - 21 -1257.920020183552 - 72 - 1 - 10 -3431.364366980768 - 20 -1257.920020183552 - 11 -3431.59436698075 - 21 -1257.920020183552 - 72 - 1 - 10 -3431.59436698075 - 20 -1257.920020183552 - 11 -3431.59436698075 - 21 -1258.020020183528 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B2A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1258.040620183477 - 11 -3431.364366980768 - 21 -1258.040620183477 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.040620183477 - 11 -3431.364366980768 - 21 -1257.6906201835 - 72 - 1 - 10 -3431.364366980768 - 20 -1257.6906201835 - 11 -3431.59436698075 - 21 -1257.6906201835 - 72 - 1 - 10 -3431.59436698075 - 20 -1257.6906201835 - 11 -3431.59436698075 - 21 -1258.040620183477 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B2B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1258.090620183524 - 11 -3431.364366980768 - 21 -1258.090620183524 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.090620183524 - 11 -3431.364366980768 - 21 -1258.040620183477 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.040620183477 - 11 -3431.59436698075 - 21 -1258.040620183477 - 72 - 1 - 10 -3431.59436698075 - 20 -1258.040620183477 - 11 -3431.59436698075 - 21 -1258.090620183524 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B2C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.370020183505 - 11 -3430.764366980675 - 21 -1258.370020183505 - 72 - 1 - 10 -3430.764366980675 - 20 -1258.370020183505 - 11 -3430.764366980675 - 21 -1258.270020183529 - 72 - 1 - 10 -3430.764366980675 - 20 -1258.270020183529 - 11 -3431.364366980768 - 21 -1258.270020183529 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.270020183529 - 11 -3431.364366980768 - 21 -1258.370020183505 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B2D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980736 - 20 -1257.590620183502 - 10 -3431.364366980736 - 20 -1258.040620183456 - 10 -3431.594366980717 - 20 -1258.040620183456 - 10 -3431.594366980717 - 20 -1257.590620183502 - 0 -LWPOLYLINE - 5 -B2E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980736 - 20 -1258.040620183456 - 10 -3431.364366980736 - 20 -1258.090620183502 - 10 -3431.594366980717 - 20 -1258.090620183502 - 10 -3431.594366980717 - 20 -1258.040620183456 - 0 -LWPOLYLINE - 5 -B2F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3429.260147392666 - 20 -1245.631902978352 - 10 -3429.255147392662 - 20 -1246.986620183514 - 10 -3429.255147392662 - 20 -1247.186620183525 - 10 -3429.485147392643 - 20 -1247.186620183525 - 10 -3429.485147392643 - 20 -1245.631902978352 - 0 -LINE - 5 -B30 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbLine - 10 -3426.51679551465 - 20 -1246.986620183514 - 11 -3426.51679551465 - 21 -1246.726972465814 - 0 -LINE - 5 -B31 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbLine - 10 -3426.610354400156 - 20 -1246.986620183514 - 11 -3426.610354400156 - 21 -1246.726972465814 - 0 -LINE - 5 -B32 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbLine - 10 -3426.719510730157 - 20 -1246.986620183514 - 11 -3426.719510730157 - 21 -1246.726972465814 - 0 -LINE - 5 -B33 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbLine - 10 -3427.358851265428 - 20 -1246.986620183514 - 11 -3427.358851265428 - 21 -1246.726972465814 - 0 -LINE - 5 -B34 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbLine - 10 -3427.452410150934 - 20 -1246.986620183514 - 11 -3427.452410150934 - 21 -1246.726972465814 - 0 -LINE - 5 -B35 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbLine - 10 -3427.561566480934 - 20 -1246.986620183514 - 11 -3427.561566480934 - 21 -1246.726972465814 - 0 -LINE - 5 -B36 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbLine - 10 -3427.998204691252 - 20 -1246.986620183514 - 11 -3427.998204691252 - 21 -1246.726972465814 - 0 -LINE - 5 -B37 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3428.091763576759 - 20 -1246.986620183514 - 11 -3428.091763576759 - 21 -1246.726972465814 - 0 -LINE - 5 -B38 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3428.200919906758 - 20 -1246.986620183514 - 11 -3428.200919906758 - 21 -1246.726972465814 - 0 -LINE - 5 -B39 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3428.699922113712 - 20 -1246.986620183514 - 11 -3428.699922113712 - 21 -1246.726972465814 - 0 -LINE - 5 -B3A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3428.793480999335 - 20 -1246.986620183514 - 11 -3428.793480999335 - 21 -1246.726972465814 - 0 -LINE - 5 -B3B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3428.902637329218 - 20 -1246.986620183514 - 11 -3428.902637329218 - 21 -1246.726972465814 - 0 -LEADER - 5 -B3C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLeader - 3 -Standard - 71 - 1 - 72 - 0 - 73 - 3 - 74 - 0 - 75 - 0 - 40 -1 - 41 -10 - 76 -3 - 76 -3 - 10 -3429.255147392662 - 20 -1248.186620183525 - 30 -0 - 10 -3429.255147392662 - 20 -1249.055130511409 - 30 -0 - 10 -3428.107193445356 - 20 -1249.055130511409 - 30 -0 - 0 -LEADER - 5 -B3D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLeader - 3 -Standard - 71 - 1 - 72 - 0 - 73 - 3 - 74 - 0 - 75 - 0 - 40 -1 - 41 -10 - 76 -3 - 76 -3 - 10 -3429.485147392643 - 20 -1247.812661133244 - 30 -0 - 10 -3429.984339434687 - 20 -1247.812661133244 - 30 -0 - 10 -3429.984339434687 - 20 -1249.558370642658 - 30 -0 - 0 -MTEXT - 5 -B3E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3424.709583766791 - 20 -1247.229278560964 - 30 -0 - 40 -0.2 - 41 -1.105555555555556 - 71 - 1 - 72 - 5 - 1 -G Level\P+/-0 Lvl - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -B3F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3428.061230431111 - 20 -1249.304358304656 - 30 -0 - 40 -0.1457306057650888 - 41 -1.339911927667163 - 71 - 1 - 72 - 5 - 1 -Site boundary - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -B40 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3429.291750858221 - 20 -1249.7602796678 - 30 -0 - 40 -0.1457306057650888 - 41 -2.611006761571927 - 71 - 1 - 72 - 5 - 1 -Applicants compound wall - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -B41 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3430.764366980675 - 20 -1247.78662018356 - 10 -3430.764366980675 - 20 -1247.986620183514 - 10 -3430.864366980768 - 20 -1247.986620183514 - 10 -3430.864366980768 - 20 -1247.78662018356 - 0 -LINE - 5 -B42 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3430.864366980768 - 20 -1247.986620183514 - 11 -3431.364366980768 - 21 -1247.986620183514 - 0 -LWPOLYLINE - 5 -B43 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3430.764366980643 - 20 -1250.614136013726 - 10 -3430.764366980643 - 20 -1250.814136013738 - 10 -3430.864366980735 - 20 -1250.814136013738 - 10 -3430.864366980735 - 20 -1250.614136013726 - 0 -LINE - 5 -B44 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3430.864366980735 - 20 -1250.814136013738 - 11 -3431.364366980736 - 21 -1250.814136013738 - 0 -LWPOLYLINE - 5 -B45 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3430.764366980643 - 20 -1254.771631514653 - 10 -3430.764366980643 - 20 -1254.971631514665 - 10 -3430.864366980735 - 20 -1254.971631514665 - 10 -3430.864366980735 - 20 -1254.771631514653 - 0 -LINE - 5 -B46 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3430.864366980768 - 20 -1254.971631514669 - 11 -3431.364366980768 - 21 -1254.971631514669 - 0 -LWPOLYLINE - 5 -B47 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3430.764366980643 - 20 -1258.370020183502 - 10 -3430.764366980643 - 20 -1258.570020183513 - 10 -3430.864366980735 - 20 -1258.570020183513 - 10 -3430.864366980735 - 20 -1258.370020183502 - 0 -LINE - 5 -B48 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3430.864366980768 - 20 -1258.570020183517 - 11 -3431.364366980768 - 21 -1258.570020183517 - 0 -HATCH - 5 -B49 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.364366980768 - 20 -1261.986620183514 - 11 -3431.59436698075 - 21 -1261.986620183514 - 72 - 1 - 10 -3431.59436698075 - 20 -1261.986620183514 - 11 -3431.59436698075 - 21 -1262.286620183502 - 72 - 1 - 10 -3431.59436698075 - 20 -1262.28662018356 - 11 -3431.364366980768 - 21 -1262.28662018356 - 72 - 1 - 10 -3431.364366980768 - 20 -1262.28662018356 - 11 -3431.364366980768 - 21 -1261.986620183572 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B4A -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.364366980768 - 20 -1262.08932542452 - 11 -3430.764366980675 - 21 -1262.08932542452 - 72 - 1 - 10 -3430.764366980675 - 20 -1262.08932542452 - 11 -3430.764366980675 - 21 -1261.989325424485 - 72 - 1 - 10 -3430.764366980675 - 20 -1261.989325424485 - 11 -3431.364366980768 - 21 -1261.989325424485 - 72 - 1 - 10 -3431.364366980768 - 20 -1261.989325424485 - 11 -3431.364366980768 - 21 -1262.08932542452 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B4B -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980768 - 20 -1261.836620183549 - 10 -3431.364366980768 - 20 -1262.189325424497 - 10 -3431.59436698075 - 20 -1262.189325424497 - 10 -3431.59436698075 - 20 -1261.739325424485 - 0 -LWPOLYLINE - 5 -B4C -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3430.764366980876 - 20 -1262.189325424493 - 10 -3430.764366980876 - 20 -1262.089325424516 - 10 -3431.364366980968 - 20 -1262.089325424516 - 0 -LWPOLYLINE - 5 -B4D -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980768 - 20 -1262.189325424497 - 10 -3431.364366980768 - 20 -1262.239325424485 - 10 -3431.59436698075 - 20 -1262.239325424485 - 10 -3431.59436698075 - 20 -1262.189325424497 - 0 -LWPOLYLINE - 5 -B4E -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3430.764366980675 - 20 -1262.08932542452 - 10 -3430.764366980675 - 20 -1262.289325424532 - 10 -3430.864366980768 - 20 -1262.289325424532 - 10 -3430.864366980768 - 20 -1262.08932542452 - 0 -LWPOLYLINE - 5 -B4F -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3434.864366968195 - 20 -1262.189325424497 - 10 -3434.864366968195 - 20 -1262.28662018356 - 10 -3431.364366980768 - 20 -1262.28662018356 - 0 -LWPOLYLINE - 5 -B50 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3431.594366980717 - 20 -1262.186620183522 - 10 -3431.594366980717 - 20 -1262.286620183557 - 10 -3434.864366968162 - 20 -1262.286620183557 - 10 -3434.864366968162 - 20 -1262.189325424493 - 10 -3431.594366980717 - 20 -1262.186620183522 - 0 -LINE - 5 -B51 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbLine - 10 -3431.364366980768 - 20 -1262.28662018356 - 11 -3430.864366980768 - 21 -1262.28662018356 - 0 -HATCH - 5 -B52 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3434.344366980633 - 20 -1256.28662018356 - 11 -3434.244366980773 - 21 -1256.28662018356 - 72 - 1 - 10 -3434.244366980773 - 20 -1256.28662018356 - 11 -3434.244366980773 - 21 -1256.186620183525 - 72 - 1 - 10 -3434.244366980773 - 20 -1256.186620183525 - 11 -3434.344366980633 - 21 -1256.186620183525 - 72 - 1 - 10 -3434.344366980633 - 20 -1256.186620183525 - 11 -3434.344366980633 - 21 -1256.28662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B53 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1258.021631514657 - 11 -3431.364366980768 - 21 -1258.021631514657 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.021631514657 - 11 -3431.364366980768 - 21 -1257.92163151468 - 72 - 1 - 10 -3431.364366980768 - 20 -1257.92163151468 - 11 -3431.59436698075 - 21 -1257.92163151468 - 72 - 1 - 10 -3431.59436698075 - 20 -1257.92163151468 - 11 -3431.59436698075 - 21 -1258.021631514657 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B54 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1258.042231514664 - 11 -3431.364366980768 - 21 -1258.042231514664 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.042231514664 - 11 -3431.364366980768 - 21 -1257.692231514629 - 72 - 1 - 10 -3431.364366980768 - 20 -1257.692231514629 - 11 -3431.59436698075 - 21 -1257.692231514629 - 72 - 1 - 10 -3431.59436698075 - 20 -1257.692231514629 - 11 -3431.59436698075 - 21 -1258.042231514664 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B55 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1258.092231514652 - 11 -3431.364366980768 - 21 -1258.092231514652 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.092231514652 - 11 -3431.364366980768 - 21 -1258.042231514664 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.042231514664 - 11 -3431.59436698075 - 21 -1258.042231514664 - 72 - 1 - 10 -3431.59436698075 - 20 -1258.042231514664 - 11 -3431.59436698075 - 21 -1258.092231514652 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B56 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.371631514692 - 11 -3430.764366980675 - 21 -1258.371631514692 - 72 - 1 - 10 -3430.764366980675 - 20 -1258.371631514692 - 11 -3430.764366980675 - 21 -1258.271631514657 - 72 - 1 - 10 -3430.764366980675 - 20 -1258.271631514657 - 11 -3431.364366980768 - 21 -1258.271631514657 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.271631514657 - 11 -3431.364366980768 - 21 -1258.371631514692 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B57 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980736 - 20 -1257.622231514601 - 10 -3431.364366980736 - 20 -1258.092231514631 - 10 -3431.594366980717 - 20 -1258.092231514631 - 10 -3431.594366980717 - 20 -1257.592231514631 - 0 -LWPOLYLINE - 5 -B58 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3430.764366980643 - 20 -1258.371631514688 - 10 -3430.764366980643 - 20 -1258.5716315147 - 10 -3430.864366980735 - 20 -1258.5716315147 - 10 -3430.864366980735 - 20 -1258.371631514688 - 0 -LINE - 5 -B59 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3430.864366980768 - 20 -1258.571631514704 - 11 -3431.364366980768 - 21 -1258.571631514704 - 0 -LINE - 5 -B5A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3434.864366968162 - 20 -1261.231902978325 - 11 -3448.48983535287 - 21 -1261.231902978325 - 0 -LWPOLYLINE - 5 -B5B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3434.864366968162 - 20 -1261.231902978325 - 10 -3434.864366968162 - 20 -1260.781902978313 - 10 -3448.48983535287 - 20 -1260.781902978313 - 0 -LINE - 5 -B5C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.364366980768 - 20 -1248.636620183537 - 11 -3424.624974634298 - 21 -1248.636620183537 - 0 -LINE - 5 -B5D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.364289394499 - 20 -1252.686624971338 - 11 -3424.624897048027 - 21 -1252.686624971338 - 0 -LINE - 5 -B5E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.364366980768 - 20 -1256.28662018356 - 11 -3424.624974634298 - 21 -1256.28662018356 - 0 -LINE - 5 -B5F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.364366980768 - 20 -1259.886620183537 - 11 -3424.624974634298 - 21 -1259.886620183537 - 0 -DIMENSION - 5 -B60 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 5 -100 -AcDbDimension - 2 -*D76 - 10 -3427.522237369113 - 20 -1248.636620183537 - 30 -0 - 11 -3427.394713937245 - 21 -1247.811620183526 - 31 -0 - 70 - 33 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3427.76242944449 - 23 -1246.986620183514 - 33 -0 - 14 -3427.76242944449 - 24 -1248.636620183537 - 34 -0 - 0 -DIMENSION - 5 -B61 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 255 -370 - 5 -100 -AcDbDimension - 2 -*D77 - 10 -3427.52223736918 - 20 -1252.686624971338 - 30 -0 - 11 -3427.394713937312 - 21 -1250.661622577436 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3427.762429444553 - 23 -1248.636620183537 - 33 -0 - 14 -3427.994593221313 - 24 -1252.686624971338 - 34 -0 - 50 -270 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -B62 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D78 - 10 -3427.522237369127 - 20 -1256.28662018356 - 30 -0 - 11 -3427.394713937259 - 21 -1254.486622577448 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3427.994593221261 - 23 -1252.686624971338 - 33 -0 - 14 -3427.522237369125 - 24 -1256.28662018356 - 34 -0 - 50 -270 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -B63 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 5 -100 -AcDbDimension - 2 -*D79 - 10 -3427.522237369135 - 20 -1259.886620183537 - 30 -0 - 11 -3427.394713937268 - 21 -1258.086620183549 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3427.522237369135 - 23 -1256.28662018356 - 33 -0 - 14 -3427.522237369135 - 24 -1259.886620183537 - 34 -0 - 50 -270 -100 -AcDbRotatedDimension - 0 -MTEXT - 5 -B64 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3424.612683876567 - 20 -1249.226913949711 - 30 -0 - 40 -0.2 - 41 -1.661111111111139 - 71 - 1 - 72 - 5 - 1 -ground floor\PFFL\P+1.65 Lvl - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -B65 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3424.612683876567 - 20 -1253.274124337131 - 30 -0 - 40 -0.2 - 41 -1.372222325079662 - 71 - 1 - 72 - 5 - 1 -first floor\PFFL\P+5.70 Lvl - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -B66 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3424.612683876567 - 20 -1256.884222381519 - 30 -0 - 40 -0.2 - 41 -1.661187305516043 - 71 - 1 - 72 - 5 - 1 -second floor\PFFL\P+9.30 Lvl - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -B67 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3424.612683876567 - 20 -1260.470465333437 - 30 -0 - 40 -0.2 - 41 -1.75000000000001 - 71 - 1 - 72 - 5 - 1 -terrace floor\PFFL\P+12.90 Lvl - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -LINE - 5 -B68 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.364366980768 - 20 -1245.78662018356 - 11 -3424.624974634298 - 21 -1245.78662018356 - 0 -MTEXT - 5 -B69 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3424.612683876567 - 20 -1246.385440453483 - 30 -0 - 40 -0.2 - 41 -2.016666769524143 - 71 - 1 - 72 - 5 - 1 -basement floor\PFFL\P-1.20 Lvl - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -B6A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3438.407092350452 - 20 -1260.178373193954 - 30 -0 - 40 -0.2 - 41 -0.9333333333333427 - 71 - 1 - 72 - 5 - 1 -terrace - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -DIMENSION - 5 -B6B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 5 -100 -AcDbDimension - 2 -*D80 - 10 -3427.522237369113 - 20 -1245.78662018356 - 30 -0 - 11 -3427.394713937245 - 21 -1246.386620183537 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3427.76242944449 - 23 -1246.986620183514 - 33 -0 - 14 -3427.671571185602 - 24 -1245.78662018356 - 34 -0 - 50 -270 -100 -AcDbRotatedDimension - 0 -MTEXT - 5 -B6C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3431.682673379422 - 20 -1251.150940983967 - 30 -0 - 40 -0.1 - 41 -0.6777777777777824 - 71 - 1 - 72 - 5 - 1 -rise=.176\Ptread=0.20 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883538 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -B6D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3462.358168989803 - 20 -1245.025794498335 - 30 -0 - 40 -0.4900000000000003 - 41 -5.920833333333337 - 71 - 1 - 72 - 5 - 1 -FRONT ELEVATION - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -B6E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3431.835146950707 - 20 -1243.135056148811 - 30 -0 - 40 -0.4900000000000003 - 41 -4.219444340563395 - 71 - 1 - 72 - 5 - 1 -SECTION A A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LINE - 5 -B6F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.820140817352 - 20 -1247.434328626845 - 11 -3471.050140817417 - 21 -1247.434328626845 - 0 -LINE - 5 -B70 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.820140817352 - 20 -1247.244892983875 - 11 -3471.050140817417 - 21 -1247.244892983875 - 0 -LINE - 5 -B71 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.820140817352 - 20 -1247.136635363455 - 11 -3471.050140817417 - 21 -1247.136635363455 - 0 -DIMENSION - 5 -B72 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D81 - 10 -3430.011031889974 - 20 -1246.989735042331 - 30 -0 - 11 -3429.883508458106 - 21 -1247.588177612927 - 31 -0 - 70 - 33 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3429.485147392643 - 23 -1248.186620183525 - 33 -0 - 14 -3429.485147392643 - 24 -1246.989735042331 - 34 -0 - 0 -DIMENSION - 5 -B73 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D82 - 10 -3430.011031889974 - 20 -1245.631902978342 - 30 -0 - 11 -3429.883508458106 - 21 -1246.31081901033 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3429.485147392643 - 23 -1246.989735042321 - 33 -0 - 14 -3429.485147392643 - 24 -1245.631902978342 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -B74 -100 -AcDbEntity - 8 -BLK_1_FLR_0_HT_ROOM - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D83 - 10 -3439.369119896593 - 20 -1248.636620183537 - 30 -0 - 11 -3439.369119896593 - 21 -1250.661620183561 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3438.054366980713 - 23 -1252.686620183584 - 33 -0 - 14 -3438.054366980713 - 24 -1248.636620183537 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -B75 -100 -AcDbEntity - 8 -BLK_1_FLR_1_HT_ROOM - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D84 - 10 -3439.379987518114 - 20 -1256.28662018356 - 30 -0 - 11 -3439.379987518114 - 21 -1254.486620183572 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3439.078499989153 - 23 -1252.686620183584 - 33 -0 - 14 -3440.061276775585 - 24 -1256.28662018356 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -B76 -100 -AcDbEntity - 8 -BLK_1_FLR_2_HT_ROOM - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D85 - 10 -3440.165820340022 - 20 -1256.28662018356 - 30 -0 - 11 -3440.165820340022 - 21 -1258.086620183374 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3440.149415793408 - 23 -1259.886620183188 - 33 -0 - 14 -3440.149415793408 - 24 -1256.28662018356 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -B77 -100 -AcDbEntity - 8 -BLK_1_HT_OF_BLDG - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D86 - 10 -3451.236564734482 - 20 -1246.986620184678 - 30 -0 - 11 -3451.236564734482 - 21 -1253.436620184108 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3448.489835352904 - 23 -1259.886620183537 - 33 -0 - 14 -3453.888227601801 - 24 -1246.986620184678 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -LWPOLYLINE - 5 -B78 -100 -AcDbEntity - 8 -BLK_1_BSMNT_FOOT_PRINT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 11 - 70 - 1 - 43 -0 - 10 -3699.232777040192 - 20 -1130.901118105119 - 10 -3710.930247410173 - 20 -1130.901118105119 - 10 -3710.930247410173 - 20 -1115.444751510471 - 10 -3707.700247410171 - 20 -1115.444751510471 - 10 -3707.700247410171 - 20 -1115.044751510448 - 10 -3704.466422993662 - 20 -1115.044751509982 - 10 -3704.466422993662 - 20 -1114.343383919057 - 10 -3702.961422993541 - 20 -1114.343383919057 - 10 -3702.961422993541 - 20 -1113.775649733043 - 10 -3699.465042147525 - 20 -1113.775649733043 - 10 -3699.232777040069 - 20 -1113.775649733053 - 0 -LINE - 5 -B79 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.224476717306 - 20 -1245.352369954856 - 11 -3301.124476717212 - 21 -1243.552369962679 - 0 -LINE - 5 -B7A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1245.352369962667 - 11 -3300.224476717306 - 21 -1243.552390304204 - 0 -LINE - 5 -B7B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077781888094 - 20 -1245.352369962667 - 11 -3317.977986022152 - 21 -1243.552369962679 - 0 -LINE - 5 -B7C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611773763 - 20 -1243.552369962679 - 11 -3317.977986019338 - 21 -1245.352369962667 - 0 -LINE - 5 -B7D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1245.352369962667 - 11 -3353.288675249574 - 21 -1243.552384968265 - 0 -LINE - 5 -B7E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288675249575 - 20 -1245.352369952924 - 11 -3354.188675249481 - 21 -1243.552369964251 - 0 -LWPOLYLINE - 5 -B7F -100 -AcDbEntity - 8 -PLOT_BOUNDARY - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 1 - 43 -0 - 10 -3698.034300625808 - 20 -1132.82980976987 - 10 -3701.361437638996 - 20 -1133.220526157112 - 10 -3710.910329968247 - 20 -1133.07507759163 - 10 -3711.148205478351 - 20 -1109.627121782186 - 10 -3698.034300625808 - 20 -1107.078893492156 - 0 -LWPOLYLINE - 5 -B80 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3305.8319470861 - 20 -1243.423737553594 - 10 -3307.0319470861 - 20 -1243.423737553594 - 10 -3307.0319470861 - 20 -1241.218060514017 - 10 -3305.8319470861 - 20 -1241.218060514017 - 0 -LWPOLYLINE - 5 -B81 -100 -AcDbEntity - 8 -BLK_1_FLR_1_URINAL - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3317.682038925002 - 20 -1259.050104148744 - 10 -3318.282038925001 - 20 -1259.050104148744 - 10 -3318.282038925001 - 20 -1258.350104148744 - 10 -3317.682038925002 - 20 -1258.350104148744 - 0 -LWPOLYLINE - 5 -B82 -100 -AcDbEntity - 8 -BLK_1_FLR_1_URINAL - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3318.282038924955 - 20 -1259.050104146998 - 10 -3318.882038924955 - 20 -1259.050104146998 - 10 -3318.882038924955 - 20 -1258.350104146998 - 10 -3318.282038924955 - 20 -1258.350104146998 - 0 -LWPOLYLINE - 5 -B83 -100 -AcDbEntity - 8 -BLK_1_FLR_1_URINAL - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3318.882038924909 - 20 -1259.050104148744 - 10 -3319.482038924909 - 20 -1259.050104148744 - 10 -3319.482038924909 - 20 -1258.350104148744 - 10 -3318.882038924909 - 20 -1258.350104148744 - 0 -LWPOLYLINE - 5 -B84 -100 -AcDbEntity - 8 -BLK_1_FLR_1_WASH - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3320.693525724812 - 20 -1256.50374874116 - 10 -3320.693525724812 - 20 -1256.951083195586 - 10 -3320.379812578121 - 20 -1256.951083195586 - 10 -3320.379812578121 - 20 -1256.50374874116 - 0 -INSERT - 5 -B85 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3320.700460489955 - 20 -1256.704804335515 - 30 -0 - 41 --0.5904899999997447 - 42 -0.5904900000003975 - 43 -0 - 50 -269.9561751820622 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -LWPOLYLINE - 5 -B86 -100 -AcDbEntity - 8 -BLK_1_FLR_1_WASH - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3320.689148559377 - 20 -1256.951083195586 - 10 -3320.689148559377 - 20 -1257.398417650012 - 10 -3320.375435412687 - 20 -1257.398417650012 - 10 -3320.375435412687 - 20 -1256.951083195586 - 0 -INSERT - 5 -B87 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3320.69608332452 - 20 -1257.152138789941 - 30 -0 - 41 --0.5904899999997446 - 42 -0.5904900000003975 - 43 -0 - 50 -269.9561751820622 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -LINE - 5 -B88 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.169366980704 - 20 -1243.831902978422 - 11 -3445.169366980703 - 21 -1243.831902978422 - 0 -LINE - 5 -B89 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.169366980704 - 20 -1243.681902978398 - 11 -3445.169366980703 - 21 -1243.681902978398 - 0 -LINE - 5 -B8A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.169366980704 - 20 -1243.561902978403 - 11 -3445.169366980703 - 21 -1243.561902978403 - 0 -LINE - 5 -B8B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.169366980704 - 20 -1243.561902978403 - 11 -3444.169366980704 - 21 -1243.831902978422 - 0 -LINE - 5 -B8C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3445.169366980703 - 20 -1243.561902978403 - 11 -3445.169366980703 - 21 -1243.831902978422 - 0 -LINE - 5 -B8D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.454366980853 - 20 -1244.13190297841 - 11 -3444.169366980704 - 21 -1243.831902978422 - 0 -LINE - 5 -B8E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.884366980788 - 20 -1244.13190297841 - 11 -3445.169366980703 - 21 -1243.831902978422 - 0 -LINE - 5 -B8F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.454366980853 - 20 -1244.13190297841 - 11 -3444.884366980788 - 21 -1244.13190297841 - 0 -LWPOLYLINE - 5 -B90 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3444.554366980713 - 20 -1245.631902978352 - 10 -3444.554366980713 - 20 -1244.131902978352 - 10 -3444.784366980695 - 20 -1244.131902978352 - 10 -3444.784366980695 - 20 -1245.631902978352 - 10 -3444.554366980713 - 20 -1245.631902978352 - 0 -LINE - 5 -B91 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.874835352739 - 20 -1243.831902978422 - 11 -3448.874835352739 - 21 -1243.831902978422 - 0 -LINE - 5 -B92 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.874835352739 - 20 -1243.681902978398 - 11 -3448.874835352739 - 21 -1243.681902978398 - 0 -LINE - 5 -B93 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.874835352739 - 20 -1243.561902978403 - 11 -3448.874835352739 - 21 -1243.561902978403 - 0 -LINE - 5 -B94 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.874835352739 - 20 -1243.561902978403 - 11 -3447.874835352739 - 21 -1243.831902978422 - 0 -LINE - 5 -B95 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.874835352739 - 20 -1243.561902978403 - 11 -3448.874835352739 - 21 -1243.831902978422 - 0 -LINE - 5 -B96 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.159835352889 - 20 -1244.13190297841 - 11 -3447.874835352739 - 21 -1243.831902978422 - 0 -LINE - 5 -B97 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.589835352823 - 20 -1244.13190297841 - 11 -3448.874835352739 - 21 -1243.831902978422 - 0 -LINE - 5 -B98 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.159835352889 - 20 -1244.13190297841 - 11 -3448.589835352823 - 21 -1244.13190297841 - 0 -LWPOLYLINE - 5 -B99 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3448.259835352749 - 20 -1245.631902978352 - 10 -3448.259835352749 - 20 -1244.131902978352 - 10 -3448.48983535273 - 20 -1244.131902978352 - 10 -3448.48983535273 - 20 -1245.631902978352 - 10 -3448.259835352749 - 20 -1245.631902978352 - 0 -LINE - 5 -B9A -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3440.669366980703 - 20 -1243.831902978422 - 11 -3441.669366980703 - 21 -1243.831902978422 - 0 -LINE - 5 -B9B -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3440.669366980703 - 20 -1243.681902978398 - 11 -3441.669366980703 - 21 -1243.681902978398 - 0 -LINE - 5 -B9C -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3440.669366980703 - 20 -1243.561902978403 - 11 -3441.669366980703 - 21 -1243.561902978403 - 0 -LINE - 5 -B9D -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3440.669366980703 - 20 -1243.561902978403 - 11 -3440.669366980703 - 21 -1243.831902978422 - 0 -LINE - 5 -B9E -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3441.669366980703 - 20 -1243.561902978403 - 11 -3441.669366980703 - 21 -1243.831902978422 - 0 -LINE - 5 -B9F -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3440.954366980852 - 20 -1244.13190297841 - 11 -3440.669366980703 - 21 -1243.831902978422 - 0 -LINE - 5 -BA0 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3441.384366980787 - 20 -1244.13190297841 - 11 -3441.669366980703 - 21 -1243.831902978422 - 0 -LINE - 5 -BA1 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3440.954366980852 - 20 -1244.13190297841 - 11 -3441.384366980787 - 21 -1244.13190297841 - 0 -LWPOLYLINE - 5 -BA2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3441.054366980712 - 20 -1245.631902978352 - 10 -3441.054366980712 - 20 -1244.131902978352 - 10 -3441.284366980692 - 20 -1244.131902978352 - 10 -3441.284366980692 - 20 -1245.631902978352 - 10 -3441.054366980712 - 20 -1245.631902978352 - 0 -LINE - 5 -BA3 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3437.439366980767 - 20 -1243.831902978422 - 11 -3438.439366980766 - 21 -1243.831902978422 - 0 -LINE - 5 -BA4 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3437.439366980767 - 20 -1243.681902978398 - 11 -3438.439366980766 - 21 -1243.681902978398 - 0 -LINE - 5 -BA5 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3437.439366980767 - 20 -1243.561902978403 - 11 -3438.439366980766 - 21 -1243.561902978403 - 0 -LINE - 5 -BA6 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3437.439366980767 - 20 -1243.561902978403 - 11 -3437.439366980767 - 21 -1243.831902978422 - 0 -LINE - 5 -BA7 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3438.439366980766 - 20 -1243.561902978403 - 11 -3438.439366980766 - 21 -1243.831902978422 - 0 -LINE - 5 -BA8 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3437.724366980916 - 20 -1244.13190297841 - 11 -3437.439366980767 - 21 -1243.831902978422 - 0 -LINE - 5 -BA9 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3438.15436698085 - 20 -1244.13190297841 - 11 -3438.439366980766 - 21 -1243.831902978422 - 0 -LINE - 5 -BAA -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3437.724366980916 - 20 -1244.13190297841 - 11 -3438.15436698085 - 21 -1244.13190297841 - 0 -LWPOLYLINE - 5 -BAB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3437.824366980776 - 20 -1245.631902978352 - 10 -3437.824366980776 - 20 -1244.131902978352 - 10 -3438.054366980757 - 20 -1244.131902978352 - 10 -3438.054366980757 - 20 -1245.631902978352 - 10 -3437.824366980776 - 20 -1245.631902978352 - 0 -LINE - 5 -BAC -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3434.479366968187 - 20 -1243.831902978422 - 11 -3435.479366968186 - 21 -1243.831902978422 - 0 -LINE - 5 -BAD -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3434.479366968187 - 20 -1243.681902978398 - 11 -3435.479366968186 - 21 -1243.681902978398 - 0 -LINE - 5 -BAE -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3434.479366968187 - 20 -1243.561902978403 - 11 -3435.479366968186 - 21 -1243.561902978403 - 0 -LINE - 5 -BAF -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3434.479366968187 - 20 -1243.561902978403 - 11 -3434.479366968187 - 21 -1243.831902978422 - 0 -LINE - 5 -BB0 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3435.479366968186 - 20 -1243.561902978403 - 11 -3435.479366968186 - 21 -1243.831902978422 - 0 -LINE - 5 -BB1 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3434.764366968335 - 20 -1244.13190297841 - 11 -3434.479366968187 - 21 -1243.831902978422 - 0 -LINE - 5 -BB2 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3435.19436696827 - 20 -1244.13190297841 - 11 -3435.479366968186 - 21 -1243.831902978422 - 0 -LINE - 5 -BB3 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3434.764366968335 - 20 -1244.13190297841 - 11 -3435.19436696827 - 21 -1244.13190297841 - 0 -LWPOLYLINE - 5 -BB4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3434.864366968195 - 20 -1245.631902978352 - 10 -3434.864366968195 - 20 -1244.131902978352 - 10 -3435.094366968177 - 20 -1244.131902978352 - 10 -3435.094366968177 - 20 -1245.631902978352 - 10 -3434.864366968195 - 20 -1245.631902978352 - 0 -LINE - 5 -BB5 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3430.979366980759 - 20 -1243.831902978422 - 11 -3431.979366980761 - 21 -1243.831902978422 - 0 -LINE - 5 -BB6 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3430.979366980759 - 20 -1243.681902978398 - 11 -3431.979366980761 - 21 -1243.681902978398 - 0 -LINE - 5 -BB7 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3430.979366980759 - 20 -1243.561902978403 - 11 -3431.979366980761 - 21 -1243.561902978403 - 0 -LINE - 5 -BB8 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3430.979366980759 - 20 -1243.561902978403 - 11 -3430.979366980759 - 21 -1243.831902978422 - 0 -LINE - 5 -BB9 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3431.979366980761 - 20 -1243.561902978403 - 11 -3431.979366980761 - 21 -1243.831902978422 - 0 -LINE - 5 -BBA -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3431.264366980908 - 20 -1244.13190297841 - 11 -3430.979366980759 - 21 -1243.831902978422 - 0 -LINE - 5 -BBB -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3431.694366980842 - 20 -1244.13190297841 - 11 -3431.979366980761 - 21 -1243.831902978422 - 0 -LINE - 5 -BBC -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3431.264366980908 - 20 -1244.13190297841 - 11 -3431.694366980842 - 21 -1244.13190297841 - 0 -LWPOLYLINE - 5 -BBD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3431.364366980768 - 20 -1245.631902978352 - 10 -3431.364366980768 - 20 -1244.131902978352 - 10 -3431.59436698075 - 20 -1244.131902978352 - 10 -3431.59436698075 - 20 -1245.631902978352 - 10 -3431.364366980768 - 20 -1245.631902978352 - 0 -MTEXT - 5 -BBE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3318.107607782454 - 20 -1258.23396419466 - 30 -0 - 40 -0.18 - 41 -1.530000000000028 - 71 - 1 - 72 - 5 - 1 -\pt252;Urinal - 7 -sree -210 -0 -220 -0 -230 -1 - 50 --0.008873397653922362 - 73 - 1 - 44 -1 - 0 -LINE - 5 -BBF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - -1 -100 -AcDbLine - 10 -3372.972164166813 - 20 -1255.550104161433 - 11 -3372.972236733065 - 21 -1255.780104182067 - 0 -LINE - 5 -BC0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - -1 -100 -AcDbLine - 10 -3372.572164165089 - 20 -1255.550104161259 - 11 -3372.972164166813 - 21 -1255.550104162563 - 0 -LINE - 5 -BC1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - -1 -100 -AcDbLine - 10 -3372.972164166813 - 20 -1255.550104162563 - 11 -3372.972164166813 - 21 -1255.780104162563 - 0 -LINE - 5 -BC2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - -1 -100 -AcDbLine - 10 -3372.972164166813 - 20 -1255.780104162563 - 11 -3372.572164165089 - 21 -1255.77999665458 - 0 -LWPOLYLINE - 5 -BC3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3292.840538748289 - 20 -1259.050104171597 - 10 -3290.634776905874 - 20 -1259.050104171597 - 10 -3290.634776905874 - 20 -1247.282947462919 - 10 -3292.840540971275 - 20 -1247.282947462919 - 0 -LINE - 5 -BC4 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3299.824476717156 - 20 -1258.300104148744 - 11 -3299.824476717156 - 21 -1259.050104148744 - 0 -DIMENSION - 5 -BC5 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D87 - 10 -3300.004476717158 - 20 -1258.300104148744 - 30 -0 - 11 -3299.361154752628 - 21 -1258.120104148744 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3299.824476717156 - 23 -1259.050104148744 - 33 -0 - 14 -3300.004476717158 - 24 -1258.300104148744 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -LWPOLYLINE - 5 -BC6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 21 - 70 - 0 - 43 -0 - 10 -3434.344366980751 - 20 -1248.636620183553 - 10 -3434.344366980751 - 20 -1248.812620183553 - 10 -3434.14436698075 - 20 -1248.812620183553 - 10 -3434.14436698075 - 20 -1248.988620183553 - 10 -3433.944366980751 - 20 -1248.988620183553 - 10 -3433.944366980751 - 20 -1249.164620183553 - 10 -3433.744366980751 - 20 -1249.164620183553 - 10 -3433.744366980751 - 20 -1249.340620183553 - 10 -3433.544366980751 - 20 -1249.340620183553 - 10 -3433.544366980751 - 20 -1249.516620183553 - 10 -3433.344366980751 - 20 -1249.516620183553 - 10 -3433.344366980751 - 20 -1249.692620183552 - 10 -3433.144366980751 - 20 -1249.692620183552 - 10 -3433.144366980751 - 20 -1249.868620183552 - 10 -3432.944366980752 - 20 -1249.868620183552 - 10 -3432.944366980752 - 20 -1250.044620183552 - 10 -3432.744366980752 - 20 -1250.044620183552 - 10 -3432.744366980752 - 20 -1250.220620183552 - 10 -3432.544366980752 - 20 -1250.220620183552 - 10 -3432.544366980752 - 20 -1250.396620183552 - 10 -3432.344366980752 - 20 -1250.396620183552 - 0 -LWPOLYLINE - 5 -BC7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3432.344366980752 - 20 -1250.396620183552 - 10 -3432.344366980752 - 20 -1250.572620183552 - 10 -3431.594366980752 - 20 -1250.572620183552 - 0 -LWPOLYLINE - 5 -BC8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 23 - 70 - 0 - 43 -0 - 10 -3434.24436698075 - 20 -1248.636620183553 - 10 -3434.24436698075 - 20 -1248.712620183553 - 10 -3434.044366980751 - 20 -1248.712620183553 - 10 -3434.044366980751 - 20 -1248.888620183553 - 10 -3433.844366980751 - 20 -1248.888620183553 - 10 -3433.844366980751 - 20 -1249.064620183553 - 10 -3433.644366980751 - 20 -1249.064620183553 - 10 -3433.644366980751 - 20 -1249.240620183553 - 10 -3433.444366980751 - 20 -1249.240620183553 - 10 -3433.444366980751 - 20 -1249.416620183553 - 10 -3433.244366980751 - 20 -1249.416620183553 - 10 -3433.244366980751 - 20 -1249.592620183553 - 10 -3433.044366980752 - 20 -1249.592620183553 - 10 -3433.044366980752 - 20 -1249.768620183553 - 10 -3432.844366980752 - 20 -1249.768620183553 - 10 -3432.844366980752 - 20 -1249.944620183552 - 10 -3432.644366980752 - 20 -1249.944620183552 - 10 -3432.644366980752 - 20 -1250.120620183552 - 10 -3432.444366980752 - 20 -1250.120620183552 - 10 -3432.444366980752 - 20 -1250.296620183552 - 10 -3432.244366980752 - 20 -1250.296620183552 - 10 -3432.244366980752 - 20 -1250.472620183552 - 10 -3431.594366980752 - 20 -1250.472620183552 - 0 -LWPOLYLINE - 5 -BC9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3434.24436698075 - 20 -1248.636620183553 - 10 -3434.344366980751 - 20 -1248.636620183553 - 0 -LINE - 5 -BCA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3432.344366980752 - 20 -1250.572620183552 - 11 -3432.344366980752 - 21 -1250.748620183552 - 0 -LINE - 5 -BCB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3432.344366980752 - 20 -1250.748620183552 - 11 -3431.594366980752 - 21 -1250.748620183552 - 0 -LINE - 5 -BCC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.594366980752 - 20 -1250.748620183552 - 11 -3431.594366980752 - 21 -1250.472620183552 - 0 -HATCH - 5 -BCD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 46 - 72 - 1 - 10 -3432.344366980752 - 20 -1250.572620183552 - 11 -3431.594366980752 - 21 -1250.572620183552 - 72 - 1 - 10 -3431.594366980752 - 20 -1250.572620183552 - 11 -3431.594366980752 - 21 -1250.472620183552 - 72 - 1 - 10 -3431.594366980752 - 20 -1250.472620183552 - 11 -3432.244366980752 - 21 -1250.472620183552 - 72 - 1 - 10 -3432.244366980752 - 20 -1250.472620183552 - 11 -3432.244366980752 - 21 -1250.296620183552 - 72 - 1 - 10 -3432.244366980752 - 20 -1250.296620183552 - 11 -3432.444366980752 - 21 -1250.296620183552 - 72 - 1 - 10 -3432.444366980752 - 20 -1250.296620183552 - 11 -3432.444366980752 - 21 -1250.120620183552 - 72 - 1 - 10 -3432.444366980752 - 20 -1250.120620183552 - 11 -3432.644366980752 - 21 -1250.120620183552 - 72 - 1 - 10 -3432.644366980752 - 20 -1250.120620183552 - 11 -3432.644366980752 - 21 -1249.944620183552 - 72 - 1 - 10 -3432.644366980752 - 20 -1249.944620183552 - 11 -3432.844366980752 - 21 -1249.944620183552 - 72 - 1 - 10 -3432.844366980752 - 20 -1249.944620183552 - 11 -3432.844366980752 - 21 -1249.768620183553 - 72 - 1 - 10 -3432.844366980752 - 20 -1249.768620183553 - 11 -3433.044366980752 - 21 -1249.768620183553 - 72 - 1 - 10 -3433.044366980752 - 20 -1249.768620183553 - 11 -3433.044366980752 - 21 -1249.592620183553 - 72 - 1 - 10 -3433.044366980752 - 20 -1249.592620183553 - 11 -3433.244366980751 - 21 -1249.592620183553 - 72 - 1 - 10 -3433.244366980751 - 20 -1249.592620183553 - 11 -3433.244366980751 - 21 -1249.416620183553 - 72 - 1 - 10 -3433.244366980751 - 20 -1249.416620183553 - 11 -3433.444366980751 - 21 -1249.416620183553 - 72 - 1 - 10 -3433.444366980751 - 20 -1249.416620183553 - 11 -3433.444366980751 - 21 -1249.240620183553 - 72 - 1 - 10 -3433.444366980751 - 20 -1249.240620183553 - 11 -3433.644366980751 - 21 -1249.240620183553 - 72 - 1 - 10 -3433.644366980751 - 20 -1249.240620183553 - 11 -3433.644366980751 - 21 -1249.064620183553 - 72 - 1 - 10 -3433.644366980751 - 20 -1249.064620183553 - 11 -3433.844366980751 - 21 -1249.064620183553 - 72 - 1 - 10 -3433.844366980751 - 20 -1249.064620183553 - 11 -3433.844366980751 - 21 -1248.888620183553 - 72 - 1 - 10 -3433.844366980751 - 20 -1248.888620183553 - 11 -3434.044366980751 - 21 -1248.888620183553 - 72 - 1 - 10 -3434.044366980751 - 20 -1248.888620183553 - 11 -3434.044366980751 - 21 -1248.712620183553 - 72 - 1 - 10 -3434.044366980751 - 20 -1248.712620183553 - 11 -3434.24436698075 - 21 -1248.712620183553 - 72 - 1 - 10 -3434.24436698075 - 20 -1248.712620183553 - 11 -3434.24436698075 - 21 -1248.636620183553 - 72 - 1 - 10 -3434.24436698075 - 20 -1248.636620183553 - 11 -3434.344366980751 - 21 -1248.636620183553 - 72 - 1 - 10 -3434.344366980751 - 20 -1248.636620183553 - 11 -3434.344366980751 - 21 -1248.812620183553 - 72 - 1 - 10 -3434.344366980751 - 20 -1248.812620183553 - 11 -3434.14436698075 - 21 -1248.812620183553 - 72 - 1 - 10 -3434.14436698075 - 20 -1248.812620183553 - 11 -3434.14436698075 - 21 -1248.988620183553 - 72 - 1 - 10 -3434.14436698075 - 20 -1248.988620183553 - 11 -3433.944366980751 - 21 -1248.988620183553 - 72 - 1 - 10 -3433.944366980751 - 20 -1248.988620183553 - 11 -3433.944366980751 - 21 -1249.164620183553 - 72 - 1 - 10 -3433.944366980751 - 20 -1249.164620183553 - 11 -3433.744366980751 - 21 -1249.164620183553 - 72 - 1 - 10 -3433.744366980751 - 20 -1249.164620183553 - 11 -3433.744366980751 - 21 -1249.340620183553 - 72 - 1 - 10 -3433.744366980751 - 20 -1249.340620183553 - 11 -3433.544366980751 - 21 -1249.340620183553 - 72 - 1 - 10 -3433.544366980751 - 20 -1249.340620183553 - 11 -3433.544366980751 - 21 -1249.516620183553 - 72 - 1 - 10 -3433.544366980751 - 20 -1249.516620183553 - 11 -3433.344366980751 - 21 -1249.516620183553 - 72 - 1 - 10 -3433.344366980751 - 20 -1249.516620183553 - 11 -3433.344366980751 - 21 -1249.692620183552 - 72 - 1 - 10 -3433.344366980751 - 20 -1249.692620183552 - 11 -3433.144366980751 - 21 -1249.692620183552 - 72 - 1 - 10 -3433.144366980751 - 20 -1249.692620183552 - 11 -3433.144366980751 - 21 -1249.868620183552 - 72 - 1 - 10 -3433.144366980751 - 20 -1249.868620183552 - 11 -3432.944366980752 - 21 -1249.868620183552 - 72 - 1 - 10 -3432.944366980752 - 20 -1249.868620183552 - 11 -3432.944366980752 - 21 -1250.044620183552 - 72 - 1 - 10 -3432.944366980752 - 20 -1250.044620183552 - 11 -3432.744366980752 - 21 -1250.044620183552 - 72 - 1 - 10 -3432.744366980752 - 20 -1250.044620183552 - 11 -3432.744366980752 - 21 -1250.220620183552 - 72 - 1 - 10 -3432.744366980752 - 20 -1250.220620183552 - 11 -3432.544366980752 - 21 -1250.220620183552 - 72 - 1 - 10 -3432.544366980752 - 20 -1250.220620183552 - 11 -3432.544366980752 - 21 -1250.396620183552 - 72 - 1 - 10 -3432.544366980752 - 20 -1250.396620183552 - 11 -3432.344366980752 - 21 -1250.396620183552 - 72 - 1 - 10 -3432.344366980752 - 20 -1250.396620183552 - 11 -3432.344366980752 - 21 -1250.572620183552 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -BCE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 25 - 70 - 0 - 43 -0 - 10 -3432.344366980752 - 20 -1250.748620183552 - 10 -3432.344366980752 - 20 -1250.924620183552 - 10 -3432.544366980752 - 20 -1250.924620183552 - 10 -3432.544366980752 - 20 -1251.100620183552 - 10 -3432.744366980752 - 20 -1251.100620183552 - 10 -3432.744366980752 - 20 -1251.276620183552 - 10 -3432.944366980752 - 20 -1251.276620183552 - 10 -3432.944366980752 - 20 -1251.452620183552 - 10 -3433.144366980751 - 20 -1251.452620183552 - 10 -3433.144366980751 - 20 -1251.628620183552 - 10 -3433.344366980751 - 20 -1251.628620183552 - 10 -3433.344366980751 - 20 -1251.804620183552 - 10 -3433.544366980751 - 20 -1251.804620183552 - 10 -3433.544366980751 - 20 -1251.980620183552 - 10 -3433.744366980751 - 20 -1251.980620183552 - 10 -3433.744366980751 - 20 -1252.156620183552 - 10 -3433.944366980751 - 20 -1252.156620183552 - 10 -3433.944366980751 - 20 -1252.332620183551 - 10 -3434.14436698075 - 20 -1252.332620183551 - 10 -3434.14436698075 - 20 -1252.508620183551 - 10 -3434.344366980751 - 20 -1252.508620183551 - 10 -3434.344366980751 - 20 -1252.684620183551 - 10 -3434.54436698075 - 20 -1252.684620183551 - 10 -3434.54436698075 - 20 -1252.684620183551 - 10 -3434.54436698075 - 20 -1252.684620183551 - 0 -LWPOLYLINE - 5 -BCF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 23 - 70 - 0 - 43 -0 - 10 -3432.444366980752 - 20 -1250.748620183552 - 10 -3432.444366980752 - 20 -1250.824620183552 - 10 -3432.644366980752 - 20 -1250.824620183552 - 10 -3432.644366980752 - 20 -1251.000620183552 - 10 -3432.844366980752 - 20 -1251.000620183552 - 10 -3432.844366980752 - 20 -1251.176620183552 - 10 -3433.044366980752 - 20 -1251.176620183552 - 10 -3433.044366980752 - 20 -1251.352620183552 - 10 -3433.244366980751 - 20 -1251.352620183552 - 10 -3433.244366980751 - 20 -1251.528620183552 - 10 -3433.444366980751 - 20 -1251.528620183552 - 10 -3433.444366980751 - 20 -1251.704620183552 - 10 -3433.644366980751 - 20 -1251.704620183552 - 10 -3433.644366980751 - 20 -1251.880620183552 - 10 -3433.844366980751 - 20 -1251.880620183552 - 10 -3433.844366980751 - 20 -1252.056620183552 - 10 -3434.044366980751 - 20 -1252.056620183552 - 10 -3434.044366980751 - 20 -1252.232620183552 - 10 -3434.24436698075 - 20 -1252.232620183552 - 10 -3434.24436698075 - 20 -1252.408620183551 - 10 -3434.444366980751 - 20 -1252.408620183551 - 10 -3434.444366980751 - 20 -1252.584620183551 - 10 -3434.54436698075 - 20 -1252.584620183551 - 0 -LINE - 5 -BD0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3432.344366980752 - 20 -1250.748620183552 - 11 -3432.344366980752 - 21 -1250.648620183552 - 0 -LINE - 5 -BD1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3432.344366980752 - 20 -1250.648620183552 - 11 -3432.444366980752 - 21 -1250.648620183552 - 0 -LINE - 5 -BD2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3432.444366980752 - 20 -1250.648620183552 - 11 -3432.444366980752 - 21 -1250.748620183552 - 0 -LWPOLYLINE - 5 -BD3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 50 - 70 - 0 - 43 -0 - 10 -3431.918118909449 - 20 -1254.390620183463 - 10 -3432.044366980719 - 20 -1254.390620183463 - 10 -3432.044366980719 - 20 -1254.390620183463 - 10 -3432.244366980718 - 20 -1254.390620183463 - 10 -3432.244366980718 - 20 -1254.226620183463 - 10 -3432.444366980718 - 20 -1254.226620183463 - 10 -3432.444366980718 - 20 -1254.062620183464 - 10 -3432.644366980718 - 20 -1254.062620183464 - 10 -3432.644366980718 - 20 -1253.898620183464 - 10 -3432.844366980718 - 20 -1253.898620183464 - 10 -3432.844366980718 - 20 -1253.734620183464 - 10 -3433.044366980718 - 20 -1253.734620183464 - 10 -3433.044366980718 - 20 -1253.570620183463 - 10 -3433.244366980718 - 20 -1253.570620183463 - 10 -3433.244366980718 - 20 -1253.406620183463 - 10 -3433.444366980717 - 20 -1253.406620183463 - 10 -3433.444366980717 - 20 -1253.242620183464 - 10 -3433.644366980717 - 20 -1253.242620183464 - 10 -3433.644366980717 - 20 -1253.078620183464 - 10 -3433.844366980717 - 20 -1253.078620183464 - 10 -3433.844366980717 - 20 -1252.914620183464 - 10 -3434.044366980717 - 20 -1252.914620183464 - 10 -3434.044366980717 - 20 -1252.750620183464 - 10 -3434.244366980717 - 20 -1252.750620183464 - 10 -3434.244366980717 - 20 -1252.586620183464 - 10 -3434.344366980717 - 20 -1252.586620183464 - 10 -3434.344366980717 - 20 -1252.850620183463 - 10 -3434.144366980717 - 20 -1252.850620183463 - 10 -3434.144366980717 - 20 -1253.014620183463 - 10 -3433.944366980717 - 20 -1253.014620183463 - 10 -3433.944366980717 - 20 -1253.178620183464 - 10 -3433.744366980717 - 20 -1253.178620183464 - 10 -3433.744366980717 - 20 -1253.342620183463 - 10 -3433.544366980718 - 20 -1253.342620183463 - 10 -3433.544366980718 - 20 -1253.506620183463 - 10 -3433.344366980718 - 20 -1253.506620183463 - 10 -3433.344366980718 - 20 -1253.670620183463 - 10 -3433.144366980718 - 20 -1253.670620183463 - 10 -3433.144366980718 - 20 -1253.834620183464 - 10 -3432.944366980718 - 20 -1253.834620183464 - 10 -3432.944366980718 - 20 -1253.998620183464 - 10 -3432.744366980717 - 20 -1253.998620183464 - 10 -3432.744366980717 - 20 -1254.162620183463 - 10 -3432.54436698072 - 20 -1254.162620183463 - 10 -3432.54436698072 - 20 -1254.326620183463 - 10 -3432.344366980718 - 20 -1254.326620183463 - 10 -3432.344366980718 - 20 -1254.490620183463 - 10 -3432.344366980718 - 20 -1254.490620183463 - 10 -3432.344366980718 - 20 -1254.490620183463 - 10 -3431.59436698075 - 20 -1254.490620183463 - 0 -LWPOLYLINE - 5 -BD4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3432.144366980719 - 20 -1254.390620183463 - 10 -3431.59436698075 - 20 -1254.390620183463 - 0 -LWPOLYLINE - 5 -BD5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3432.344366980718 - 20 -1254.654620183463 - 10 -3432.344366980718 - 20 -1254.490620183463 - 0 -LWPOLYLINE - 5 -BD6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 40 - 70 - 0 - 43 -0 - 10 -3434.244366980717 - 20 -1256.022620183525 - 10 -3434.244366980717 - 20 -1255.866620183463 - 10 -3434.044366980717 - 20 -1255.866620183463 - 10 -3434.044366980717 - 20 -1255.702620183463 - 10 -3433.844366980717 - 20 -1255.702620183463 - 10 -3433.844366980717 - 20 -1255.538620183463 - 10 -3433.644366980717 - 20 -1255.538620183463 - 10 -3433.644366980717 - 20 -1255.374620183463 - 10 -3433.444366980717 - 20 -1255.374620183463 - 10 -3433.444366980717 - 20 -1255.210620183463 - 10 -3433.244366980718 - 20 -1255.210620183463 - 10 -3433.244366980718 - 20 -1255.046620183464 - 10 -3433.044366980718 - 20 -1255.046620183464 - 10 -3433.044366980718 - 20 -1254.882620183463 - 10 -3432.844366980718 - 20 -1254.882620183463 - 10 -3432.844366980718 - 20 -1254.718620183463 - 10 -3432.644366980718 - 20 -1254.718620183463 - 10 -3432.644366980718 - 20 -1254.554620183463 - 10 -3432.444366980718 - 20 -1254.554620183463 - 10 -3432.444366980718 - 20 -1254.390620183463 - 10 -3432.344366980718 - 20 -1254.390620183463 - 10 -3432.344366980718 - 20 -1254.654620183463 - 10 -3432.54436698072 - 20 -1254.654620183463 - 10 -3432.54436698072 - 20 -1254.818620183463 - 10 -3432.744366980717 - 20 -1254.818620183463 - 10 -3432.744366980717 - 20 -1254.982620183463 - 10 -3432.944366980718 - 20 -1254.982620183463 - 10 -3432.944366980718 - 20 -1255.146620183463 - 10 -3433.144366980718 - 20 -1255.146620183463 - 10 -3433.144366980718 - 20 -1255.310620183463 - 10 -3433.344366980718 - 20 -1255.310620183463 - 10 -3433.344366980718 - 20 -1255.474620183463 - 10 -3433.544366980718 - 20 -1255.474620183463 - 10 -3433.544366980718 - 20 -1255.638620183463 - 10 -3433.744366980717 - 20 -1255.638620183463 - 10 -3433.744366980717 - 20 -1255.802620183463 - 10 -3433.944366980717 - 20 -1255.802620183463 - 10 -3433.944366980717 - 20 -1255.966620183463 - 10 -3434.144366980717 - 20 -1255.966620183463 - 10 -3434.144366980717 - 20 -1256.12262018356 - 0 -HATCH - 5 -BD7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 47 - 72 - 1 - 10 -3432.54436698072 - 20 -1254.326620183463 - 11 -3432.344366980718 - 21 -1254.326620183463 - 72 - 1 - 10 -3432.344366980718 - 20 -1254.326620183463 - 11 -3432.344366980718 - 21 -1254.490620183463 - 72 - 1 - 10 -3432.344366980718 - 20 -1254.490620183463 - 11 -3431.59436698075 - 21 -1254.490620183463 - 72 - 1 - 10 -3431.59436698075 - 20 -1254.490620183463 - 11 -3431.59436698075 - 21 -1254.390620183463 - 72 - 1 - 10 -3431.59436698075 - 20 -1254.390620183463 - 11 -3432.144366980719 - 21 -1254.390620183463 - 72 - 1 - 10 -3432.144366980719 - 20 -1254.390620183463 - 11 -3432.244366980718 - 21 -1254.390620183463 - 72 - 1 - 10 -3432.244366980718 - 20 -1254.390620183463 - 11 -3432.244366980718 - 21 -1254.226620183463 - 72 - 1 - 10 -3432.244366980718 - 20 -1254.226620183463 - 11 -3432.444366980718 - 21 -1254.226620183463 - 72 - 1 - 10 -3432.444366980718 - 20 -1254.226620183463 - 11 -3432.444366980718 - 21 -1254.062620183464 - 72 - 1 - 10 -3432.444366980718 - 20 -1254.062620183464 - 11 -3432.644366980718 - 21 -1254.062620183464 - 72 - 1 - 10 -3432.644366980718 - 20 -1254.062620183464 - 11 -3432.644366980718 - 21 -1253.898620183464 - 72 - 1 - 10 -3432.644366980718 - 20 -1253.898620183464 - 11 -3432.844366980718 - 21 -1253.898620183464 - 72 - 1 - 10 -3432.844366980718 - 20 -1253.898620183464 - 11 -3432.844366980718 - 21 -1253.734620183464 - 72 - 1 - 10 -3432.844366980718 - 20 -1253.734620183464 - 11 -3433.044366980718 - 21 -1253.734620183464 - 72 - 1 - 10 -3433.044366980718 - 20 -1253.734620183464 - 11 -3433.044366980718 - 21 -1253.570620183463 - 72 - 1 - 10 -3433.044366980718 - 20 -1253.570620183463 - 11 -3433.244366980718 - 21 -1253.570620183463 - 72 - 1 - 10 -3433.244366980718 - 20 -1253.570620183463 - 11 -3433.244366980718 - 21 -1253.406620183463 - 72 - 1 - 10 -3433.244366980718 - 20 -1253.406620183463 - 11 -3433.444366980717 - 21 -1253.406620183463 - 72 - 1 - 10 -3433.444366980717 - 20 -1253.406620183463 - 11 -3433.444366980717 - 21 -1253.242620183464 - 72 - 1 - 10 -3433.444366980717 - 20 -1253.242620183464 - 11 -3433.644366980717 - 21 -1253.242620183464 - 72 - 1 - 10 -3433.644366980717 - 20 -1253.242620183464 - 11 -3433.644366980717 - 21 -1253.078620183464 - 72 - 1 - 10 -3433.644366980717 - 20 -1253.078620183464 - 11 -3433.844366980717 - 21 -1253.078620183464 - 72 - 1 - 10 -3433.844366980717 - 20 -1253.078620183464 - 11 -3433.844366980717 - 21 -1252.914620183464 - 72 - 1 - 10 -3433.844366980717 - 20 -1252.914620183464 - 11 -3434.044366980717 - 21 -1252.914620183464 - 72 - 1 - 10 -3434.044366980717 - 20 -1252.914620183464 - 11 -3434.044366980717 - 21 -1252.750620183464 - 72 - 1 - 10 -3434.044366980717 - 20 -1252.750620183464 - 11 -3434.244366980717 - 21 -1252.750620183464 - 72 - 1 - 10 -3434.244366980717 - 20 -1252.750620183464 - 11 -3434.244366980717 - 21 -1252.586620183464 - 72 - 1 - 10 -3434.244366980717 - 20 -1252.586620183464 - 11 -3434.344366980717 - 21 -1252.586620183464 - 72 - 1 - 10 -3434.344366980717 - 20 -1252.586620183464 - 11 -3434.344366980717 - 21 -1252.850620183463 - 72 - 1 - 10 -3434.344366980717 - 20 -1252.850620183463 - 11 -3434.144366980717 - 21 -1252.850620183463 - 72 - 1 - 10 -3434.144366980717 - 20 -1252.850620183463 - 11 -3434.144366980717 - 21 -1253.014620183463 - 72 - 1 - 10 -3434.144366980717 - 20 -1253.014620183463 - 11 -3433.944366980717 - 21 -1253.014620183463 - 72 - 1 - 10 -3433.944366980717 - 20 -1253.014620183463 - 11 -3433.944366980717 - 21 -1253.178620183464 - 72 - 1 - 10 -3433.944366980717 - 20 -1253.178620183464 - 11 -3433.744366980717 - 21 -1253.178620183464 - 72 - 1 - 10 -3433.744366980717 - 20 -1253.178620183464 - 11 -3433.744366980717 - 21 -1253.342620183463 - 72 - 1 - 10 -3433.744366980717 - 20 -1253.342620183463 - 11 -3433.544366980718 - 21 -1253.342620183463 - 72 - 1 - 10 -3433.544366980718 - 20 -1253.342620183463 - 11 -3433.544366980718 - 21 -1253.506620183463 - 72 - 1 - 10 -3433.544366980718 - 20 -1253.506620183463 - 11 -3433.344366980718 - 21 -1253.506620183463 - 72 - 1 - 10 -3433.344366980718 - 20 -1253.506620183463 - 11 -3433.344366980718 - 21 -1253.670620183463 - 72 - 1 - 10 -3433.344366980718 - 20 -1253.670620183463 - 11 -3433.144366980718 - 21 -1253.670620183463 - 72 - 1 - 10 -3433.144366980718 - 20 -1253.670620183463 - 11 -3433.144366980718 - 21 -1253.834620183464 - 72 - 1 - 10 -3433.144366980718 - 20 -1253.834620183464 - 11 -3432.944366980718 - 21 -1253.834620183464 - 72 - 1 - 10 -3432.944366980718 - 20 -1253.834620183464 - 11 -3432.944366980718 - 21 -1253.998620183464 - 72 - 1 - 10 -3432.944366980718 - 20 -1253.998620183464 - 11 -3432.744366980717 - 21 -1253.998620183464 - 72 - 1 - 10 -3432.744366980717 - 20 -1253.998620183464 - 11 -3432.744366980717 - 21 -1254.162620183463 - 72 - 1 - 10 -3432.744366980717 - 20 -1254.162620183463 - 11 -3432.54436698072 - 21 -1254.162620183463 - 72 - 1 - 10 -3432.54436698072 - 20 -1254.162620183463 - 11 -3432.54436698072 - 21 -1254.326620183463 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -BD8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 50 - 70 - 0 - 43 -0 - 10 -3431.918118909449 - 20 -1257.990620183524 - 10 -3432.044366980719 - 20 -1257.990620183524 - 10 -3432.044366980719 - 20 -1257.990620183524 - 10 -3432.244366980718 - 20 -1257.990620183524 - 10 -3432.244366980718 - 20 -1257.826620183525 - 10 -3432.444366980718 - 20 -1257.826620183525 - 10 -3432.444366980718 - 20 -1257.662620183525 - 10 -3432.644366980718 - 20 -1257.662620183525 - 10 -3432.644366980718 - 20 -1257.498620183525 - 10 -3432.844366980718 - 20 -1257.498620183525 - 10 -3432.844366980718 - 20 -1257.334620183525 - 10 -3433.044366980718 - 20 -1257.334620183525 - 10 -3433.044366980718 - 20 -1257.170620183525 - 10 -3433.244366980718 - 20 -1257.170620183525 - 10 -3433.244366980718 - 20 -1257.006620183525 - 10 -3433.444366980717 - 20 -1257.006620183525 - 10 -3433.444366980717 - 20 -1256.842620183524 - 10 -3433.644366980717 - 20 -1256.842620183524 - 10 -3433.644366980717 - 20 -1256.678620183525 - 10 -3433.844366980717 - 20 -1256.678620183525 - 10 -3433.844366980717 - 20 -1256.514620183525 - 10 -3434.044366980717 - 20 -1256.514620183525 - 10 -3434.044366980717 - 20 -1256.350620183525 - 10 -3434.244366980717 - 20 -1256.350620183525 - 10 -3434.244366980717 - 20 -1256.186620183525 - 10 -3434.344366980717 - 20 -1256.186620183525 - 10 -3434.344366980717 - 20 -1256.450620183525 - 10 -3434.144366980717 - 20 -1256.450620183525 - 10 -3434.144366980717 - 20 -1256.614620183525 - 10 -3433.944366980717 - 20 -1256.614620183525 - 10 -3433.944366980717 - 20 -1256.778620183524 - 10 -3433.744366980717 - 20 -1256.778620183524 - 10 -3433.744366980717 - 20 -1256.942620183524 - 10 -3433.544366980718 - 20 -1256.942620183524 - 10 -3433.544366980718 - 20 -1257.106620183525 - 10 -3433.344366980718 - 20 -1257.106620183525 - 10 -3433.344366980718 - 20 -1257.270620183525 - 10 -3433.144366980718 - 20 -1257.270620183525 - 10 -3433.144366980718 - 20 -1257.434620183525 - 10 -3432.944366980718 - 20 -1257.434620183525 - 10 -3432.944366980718 - 20 -1257.598620183524 - 10 -3432.744366980717 - 20 -1257.598620183524 - 10 -3432.744366980717 - 20 -1257.762620183524 - 10 -3432.54436698072 - 20 -1257.762620183524 - 10 -3432.54436698072 - 20 -1257.926620183524 - 10 -3432.344366980718 - 20 -1257.926620183524 - 10 -3432.344366980718 - 20 -1258.090620183524 - 10 -3432.344366980718 - 20 -1258.090620183524 - 10 -3432.344366980718 - 20 -1258.090620183524 - 10 -3431.59436698075 - 20 -1258.090620183524 - 0 -LWPOLYLINE - 5 -BD9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3432.344366980718 - 20 -1258.254620183524 - 10 -3432.344366980718 - 20 -1258.090620183524 - 0 -LWPOLYLINE - 5 -BDA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 40 - 70 - 0 - 43 -0 - 10 -3434.244366980717 - 20 -1259.622620183586 - 10 -3434.244366980717 - 20 -1259.466620183524 - 10 -3434.044366980717 - 20 -1259.466620183524 - 10 -3434.044366980717 - 20 -1259.302620183524 - 10 -3433.844366980717 - 20 -1259.302620183524 - 10 -3433.844366980717 - 20 -1259.138620183525 - 10 -3433.644366980717 - 20 -1259.138620183525 - 10 -3433.644366980717 - 20 -1258.974620183525 - 10 -3433.444366980717 - 20 -1258.974620183525 - 10 -3433.444366980717 - 20 -1258.810620183524 - 10 -3433.244366980718 - 20 -1258.810620183524 - 10 -3433.244366980718 - 20 -1258.646620183524 - 10 -3433.044366980718 - 20 -1258.646620183524 - 10 -3433.044366980718 - 20 -1258.482620183525 - 10 -3432.844366980718 - 20 -1258.482620183525 - 10 -3432.844366980718 - 20 -1258.318620183525 - 10 -3432.644366980718 - 20 -1258.318620183525 - 10 -3432.644366980718 - 20 -1258.154620183524 - 10 -3432.444366980718 - 20 -1258.154620183524 - 10 -3432.444366980718 - 20 -1257.990620183524 - 10 -3432.344366980718 - 20 -1257.990620183524 - 10 -3432.344366980718 - 20 -1258.254620183524 - 10 -3432.54436698072 - 20 -1258.254620183524 - 10 -3432.54436698072 - 20 -1258.418620183525 - 10 -3432.744366980717 - 20 -1258.418620183525 - 10 -3432.744366980717 - 20 -1258.582620183524 - 10 -3432.944366980718 - 20 -1258.582620183524 - 10 -3432.944366980718 - 20 -1258.746620183524 - 10 -3433.144366980718 - 20 -1258.746620183524 - 10 -3433.144366980718 - 20 -1258.910620183524 - 10 -3433.344366980718 - 20 -1258.910620183524 - 10 -3433.344366980718 - 20 -1259.074620183524 - 10 -3433.544366980718 - 20 -1259.074620183524 - 10 -3433.544366980718 - 20 -1259.238620183524 - 10 -3433.744366980717 - 20 -1259.238620183524 - 10 -3433.744366980717 - 20 -1259.402620183524 - 10 -3433.944366980717 - 20 -1259.402620183524 - 10 -3433.944366980717 - 20 -1259.566620183524 - 10 -3434.144366980717 - 20 -1259.566620183524 - 10 -3434.144366980717 - 20 -1259.722620183621 - 0 -HATCH - 5 -BDB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 47 - 72 - 1 - 10 -3432.54436698072 - 20 -1257.926620183524 - 11 -3432.344366980718 - 21 -1257.926620183524 - 72 - 1 - 10 -3432.344366980718 - 20 -1257.926620183524 - 11 -3432.344366980718 - 21 -1258.090620183524 - 72 - 1 - 10 -3432.344366980718 - 20 -1258.090620183524 - 11 -3431.59436698075 - 21 -1258.090620183524 - 72 - 1 - 10 -3431.59436698075 - 20 -1258.090620183524 - 11 -3431.59436698075 - 21 -1257.990620183524 - 72 - 1 - 10 -3431.59436698075 - 20 -1257.990620183524 - 11 -3432.144366980719 - 21 -1257.990620183524 - 72 - 1 - 10 -3432.144366980719 - 20 -1257.990620183524 - 11 -3432.244366980718 - 21 -1257.990620183524 - 72 - 1 - 10 -3432.244366980718 - 20 -1257.990620183524 - 11 -3432.244366980718 - 21 -1257.826620183525 - 72 - 1 - 10 -3432.244366980718 - 20 -1257.826620183525 - 11 -3432.444366980718 - 21 -1257.826620183525 - 72 - 1 - 10 -3432.444366980718 - 20 -1257.826620183525 - 11 -3432.444366980718 - 21 -1257.662620183525 - 72 - 1 - 10 -3432.444366980718 - 20 -1257.662620183525 - 11 -3432.644366980718 - 21 -1257.662620183525 - 72 - 1 - 10 -3432.644366980718 - 20 -1257.662620183525 - 11 -3432.644366980718 - 21 -1257.498620183525 - 72 - 1 - 10 -3432.644366980718 - 20 -1257.498620183525 - 11 -3432.844366980718 - 21 -1257.498620183525 - 72 - 1 - 10 -3432.844366980718 - 20 -1257.498620183525 - 11 -3432.844366980718 - 21 -1257.334620183525 - 72 - 1 - 10 -3432.844366980718 - 20 -1257.334620183525 - 11 -3433.044366980718 - 21 -1257.334620183525 - 72 - 1 - 10 -3433.044366980718 - 20 -1257.334620183525 - 11 -3433.044366980718 - 21 -1257.170620183525 - 72 - 1 - 10 -3433.044366980718 - 20 -1257.170620183525 - 11 -3433.244366980718 - 21 -1257.170620183525 - 72 - 1 - 10 -3433.244366980718 - 20 -1257.170620183525 - 11 -3433.244366980718 - 21 -1257.006620183525 - 72 - 1 - 10 -3433.244366980718 - 20 -1257.006620183525 - 11 -3433.444366980717 - 21 -1257.006620183525 - 72 - 1 - 10 -3433.444366980717 - 20 -1257.006620183525 - 11 -3433.444366980717 - 21 -1256.842620183524 - 72 - 1 - 10 -3433.444366980717 - 20 -1256.842620183524 - 11 -3433.644366980717 - 21 -1256.842620183524 - 72 - 1 - 10 -3433.644366980717 - 20 -1256.842620183524 - 11 -3433.644366980717 - 21 -1256.678620183525 - 72 - 1 - 10 -3433.644366980717 - 20 -1256.678620183525 - 11 -3433.844366980717 - 21 -1256.678620183525 - 72 - 1 - 10 -3433.844366980717 - 20 -1256.678620183525 - 11 -3433.844366980717 - 21 -1256.514620183525 - 72 - 1 - 10 -3433.844366980717 - 20 -1256.514620183525 - 11 -3434.044366980717 - 21 -1256.514620183525 - 72 - 1 - 10 -3434.044366980717 - 20 -1256.514620183525 - 11 -3434.044366980717 - 21 -1256.350620183525 - 72 - 1 - 10 -3434.044366980717 - 20 -1256.350620183525 - 11 -3434.244366980717 - 21 -1256.350620183525 - 72 - 1 - 10 -3434.244366980717 - 20 -1256.350620183525 - 11 -3434.244366980717 - 21 -1256.186620183525 - 72 - 1 - 10 -3434.244366980717 - 20 -1256.186620183525 - 11 -3434.344366980717 - 21 -1256.186620183525 - 72 - 1 - 10 -3434.344366980717 - 20 -1256.186620183525 - 11 -3434.344366980717 - 21 -1256.450620183525 - 72 - 1 - 10 -3434.344366980717 - 20 -1256.450620183525 - 11 -3434.144366980717 - 21 -1256.450620183525 - 72 - 1 - 10 -3434.144366980717 - 20 -1256.450620183525 - 11 -3434.144366980717 - 21 -1256.614620183525 - 72 - 1 - 10 -3434.144366980717 - 20 -1256.614620183525 - 11 -3433.944366980717 - 21 -1256.614620183525 - 72 - 1 - 10 -3433.944366980717 - 20 -1256.614620183525 - 11 -3433.944366980717 - 21 -1256.778620183524 - 72 - 1 - 10 -3433.944366980717 - 20 -1256.778620183524 - 11 -3433.744366980717 - 21 -1256.778620183524 - 72 - 1 - 10 -3433.744366980717 - 20 -1256.778620183524 - 11 -3433.744366980717 - 21 -1256.942620183524 - 72 - 1 - 10 -3433.744366980717 - 20 -1256.942620183524 - 11 -3433.544366980718 - 21 -1256.942620183524 - 72 - 1 - 10 -3433.544366980718 - 20 -1256.942620183524 - 11 -3433.544366980718 - 21 -1257.106620183525 - 72 - 1 - 10 -3433.544366980718 - 20 -1257.106620183525 - 11 -3433.344366980718 - 21 -1257.106620183525 - 72 - 1 - 10 -3433.344366980718 - 20 -1257.106620183525 - 11 -3433.344366980718 - 21 -1257.270620183525 - 72 - 1 - 10 -3433.344366980718 - 20 -1257.270620183525 - 11 -3433.144366980718 - 21 -1257.270620183525 - 72 - 1 - 10 -3433.144366980718 - 20 -1257.270620183525 - 11 -3433.144366980718 - 21 -1257.434620183525 - 72 - 1 - 10 -3433.144366980718 - 20 -1257.434620183525 - 11 -3432.944366980718 - 21 -1257.434620183525 - 72 - 1 - 10 -3432.944366980718 - 20 -1257.434620183525 - 11 -3432.944366980718 - 21 -1257.598620183524 - 72 - 1 - 10 -3432.944366980718 - 20 -1257.598620183524 - 11 -3432.744366980717 - 21 -1257.598620183524 - 72 - 1 - 10 -3432.744366980717 - 20 -1257.598620183524 - 11 -3432.744366980717 - 21 -1257.762620183524 - 72 - 1 - 10 -3432.744366980717 - 20 -1257.762620183524 - 11 -3432.54436698072 - 21 -1257.762620183524 - 72 - 1 - 10 -3432.54436698072 - 20 -1257.762620183524 - 11 -3432.54436698072 - 21 -1257.926620183524 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -BDC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3430.764366980643 - 20 -1258.371631514688 - 10 -3431.364366980768 - 20 -1258.371631514688 - 10 -3431.364366980768 - 20 -1258.27323848752 - 10 -3430.764366980643 - 20 -1258.27323848752 - 0 -LWPOLYLINE - 5 -BDD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3434.144366980717 - 20 -1255.966620183463 - 10 -3434.144366980717 - 20 -1256.130620183463 - 10 -3434.344366980717 - 20 -1256.130620183463 - 10 -3434.344366980751 - 20 -1256.186620183525 - 0 -LWPOLYLINE - 5 -BDE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3434.244366980717 - 20 -1255.966620183463 - 10 -3434.244366980717 - 20 -1256.030620183463 - 10 -3434.444366980657 - 20 -1256.030620183463 - 10 -3434.444366980751 - 20 -1256.186620183465 - 0 -LWPOLYLINE - 5 -BDF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3434.144366980717 - 20 -1259.566620183524 - 10 -3434.144366980717 - 20 -1259.730620183524 - 10 -3434.344366980717 - 20 -1259.730620183524 - 10 -3434.344366980751 - 20 -1259.884787151034 - 0 -LWPOLYLINE - 5 -BE0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3434.244366980717 - 20 -1259.566620183524 - 10 -3434.244366980717 - 20 -1259.630620183524 - 10 -3434.444366980694 - 20 -1259.630620183524 - 10 -3434.444366980751 - 20 -1259.884787151012 - 0 -MTEXT - 5 -BE1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3431.682673379422 - 20 -1255.238385335864 - 30 -0 - 40 -0.1 - 41 -0.6777777777777824 - 71 - 1 - 72 - 5 - 1 -rise=0.164\Ptread=0.20 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883538 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -BE2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3431.682673379422 - 20 -1258.786671845358 - 30 -0 - 40 -0.1 - 41 -0.6777777777777824 - 71 - 1 - 72 - 5 - 1 -rise=0.164\Ptread=0.20 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883538 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -BE3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3447.212417758449 - 20 -1247.926913006706 - 30 -0 - 40 -0.1 - 41 -0.6000000000000109 - 71 - 1 - 72 - 5 - 1 -rise=0.15\Ptread=0.3 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -BE4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 19 - 70 - 0 - 43 -0 - 10 -3444.692101166711 - 20 -1245.78662018356 - 10 -3444.692101166711 - 20 -1245.93662018356 - 10 -3444.992101166711 - 20 -1245.93662018356 - 10 -3444.992101166711 - 20 -1246.08662018356 - 10 -3445.292101166711 - 20 -1246.08662018356 - 10 -3445.292101166711 - 20 -1246.23662018356 - 10 -3445.592101166711 - 20 -1246.23662018356 - 10 -3445.592101166711 - 20 -1246.38662018356 - 10 -3445.892101166712 - 20 -1246.38662018356 - 10 -3445.892101166712 - 20 -1246.53662018356 - 10 -3446.192101166712 - 20 -1246.53662018356 - 10 -3446.192101166712 - 20 -1246.68662018356 - 10 -3446.492101166712 - 20 -1246.68662018356 - 10 -3446.492101166712 - 20 -1246.836620183561 - 10 -3446.792101166713 - 20 -1246.836620183561 - 10 -3446.792101166713 - 20 -1246.986620183561 - 10 -3447.092101166712 - 20 -1246.986620183561 - 10 -3447.092101166712 - 20 -1247.13662018356 - 10 -3448.29210116671 - 20 -1247.13662018356 - 0 -LWPOLYLINE - 5 -BE5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 19 - 70 - 0 - 43 -0 - 10 -3444.792101166711 - 20 -1245.78662018356 - 10 -3444.792101166711 - 20 -1245.83662018356 - 10 -3445.092101166711 - 20 -1245.83662018356 - 10 -3445.092101166711 - 20 -1245.98662018356 - 10 -3445.392101166711 - 20 -1245.98662018356 - 10 -3445.392101166711 - 20 -1246.13662018356 - 10 -3445.692101166712 - 20 -1246.13662018356 - 10 -3445.692101166712 - 20 -1246.28662018356 - 10 -3445.992101166711 - 20 -1246.28662018356 - 10 -3445.992101166711 - 20 -1246.43662018356 - 10 -3446.292101166712 - 20 -1246.43662018356 - 10 -3446.292101166712 - 20 -1246.58662018356 - 10 -3446.592101166711 - 20 -1246.58662018356 - 10 -3446.592101166711 - 20 -1246.736620183561 - 10 -3446.892101166712 - 20 -1246.736620183561 - 10 -3446.892101166712 - 20 -1246.886620183561 - 10 -3447.192101166712 - 20 -1246.886620183561 - 10 -3447.192101166712 - 20 -1247.036620183561 - 10 -3448.29210116671 - 20 -1247.036620183561 - 0 -LINE - 5 -BE6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166712 - 20 -1247.13662018356 - 11 -3448.29210116671 - 21 -1247.13662018356 - 0 -LINE - 5 -BE7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166712 - 20 -1247.286620183561 - 11 -3448.29210116671 - 21 -1247.286620183561 - 0 -LINE - 5 -BE8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166712 - 20 -1247.436620183561 - 11 -3448.29210116671 - 21 -1247.436620183561 - 0 -LINE - 5 -BE9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166712 - 20 -1247.586620183561 - 11 -3448.29210116671 - 21 -1247.586620183561 - 0 -LWPOLYLINE - 5 -BEA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 15 - 70 - 0 - 43 -0 - 10 -3447.092101166711 - 20 -1247.586620183561 - 10 -3447.092101166711 - 20 -1247.736620183561 - 10 -3446.79210116671 - 20 -1247.736620183561 - 10 -3446.79210116671 - 20 -1247.886620183561 - 10 -3446.49210116671 - 20 -1247.886620183561 - 10 -3446.49210116671 - 20 -1248.036620183561 - 10 -3446.19210116671 - 20 -1248.036620183561 - 10 -3446.19210116671 - 20 -1248.186620183561 - 10 -3445.89210116671 - 20 -1248.186620183561 - 10 -3445.89210116671 - 20 -1248.336620183561 - 10 -3445.59210116671 - 20 -1248.336620183561 - 10 -3445.59210116671 - 20 -1248.486620183562 - 10 -3445.292101166709 - 20 -1248.486620183562 - 10 -3445.292101166709 - 20 -1248.636620183561 - 10 -3444.99210116671 - 20 -1248.636620183561 - 0 -LWPOLYLINE - 5 -BEB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 16 - 70 - 0 - 43 -0 - 10 -3446.99210116671 - 20 -1247.586620183561 - 10 -3446.99210116671 - 20 -1247.636620183561 - 10 -3446.692101166711 - 20 -1247.636620183561 - 10 -3446.692101166711 - 20 -1247.786620183561 - 10 -3446.39210116671 - 20 -1247.786620183561 - 10 -3446.39210116671 - 20 -1247.936620183561 - 10 -3446.092101166711 - 20 -1247.936620183561 - 10 -3446.092101166711 - 20 -1248.086620183561 - 10 -3445.79210116671 - 20 -1248.086620183561 - 10 -3445.79210116671 - 20 -1248.236620183561 - 10 -3445.49210116671 - 20 -1248.236620183561 - 10 -3445.49210116671 - 20 -1248.386620183562 - 10 -3445.192101166711 - 20 -1248.386620183562 - 10 -3445.192101166711 - 20 -1248.536620183562 - 10 -3444.89210116671 - 20 -1248.536620183562 - 10 -3444.89210116671 - 20 -1248.536620183562 - 0 -LWPOLYLINE - 5 -BEC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3447.092101166756 - 20 -1247.586620183561 - 10 -3447.092101166756 - 20 -1247.486620183561 - 10 -3446.99210116671 - 20 -1247.486620183559 - 10 -3446.99210116671 - 20 -1247.586620183561 - 0 -LWPOLYLINE - 5 -BED -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 35 - 70 - 0 - 43 -0 - 10 -3442.892101166711 - 20 -1248.636620183537 - 10 -3442.892101166711 - 20 -1248.786620183537 - 10 -3443.192101166711 - 20 -1248.786620183537 - 10 -3443.192101166711 - 20 -1248.936620183537 - 10 -3443.492101166711 - 20 -1248.936620183537 - 10 -3443.492101166711 - 20 -1249.086620183537 - 10 -3443.792101166711 - 20 -1249.086620183537 - 10 -3443.792101166711 - 20 -1249.236620183537 - 10 -3444.092101166711 - 20 -1249.236620183537 - 10 -3444.092101166711 - 20 -1249.386620183537 - 10 -3444.392101166712 - 20 -1249.386620183537 - 10 -3444.392101166712 - 20 -1249.536620183537 - 10 -3444.692101166712 - 20 -1249.536620183537 - 10 -3444.692101166712 - 20 -1249.686620183537 - 10 -3444.992101166711 - 20 -1249.686620183537 - 10 -3444.992101166711 - 20 -1249.836620183538 - 10 -3445.292101166713 - 20 -1249.836620183538 - 10 -3445.292101166713 - 20 -1249.986620183521 - 10 -3445.592101166712 - 20 -1249.986620183521 - 10 -3445.592101166712 - 20 -1250.136620183522 - 10 -3445.892101166712 - 20 -1250.136620183522 - 10 -3445.892101166712 - 20 -1250.286620183522 - 10 -3446.192101166712 - 20 -1250.286620183522 - 10 -3446.192101166712 - 20 -1250.436620183522 - 10 -3446.492101166712 - 20 -1250.436620183522 - 10 -3446.492101166712 - 20 -1250.586620183522 - 10 -3446.792101166713 - 20 -1250.586620183522 - 10 -3446.792101166713 - 20 -1250.736620183522 - 10 -3447.092101166714 - 20 -1250.736620183522 - 10 -3447.092101166714 - 20 -1250.886620183522 - 10 -3448.29210116671 - 20 -1250.886620183522 - 10 -3448.29210116671 - 20 -1250.886620183522 - 10 -3448.29210116671 - 20 -1250.886620183522 - 10 -3448.29210116671 - 20 -1250.886620183522 - 10 -3448.29210116671 - 20 -1250.886620183522 - 0 -LINE - 5 -BEE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166711 - 20 -1250.886620183522 - 11 -3448.29210116671 - 21 -1250.886620183522 - 0 -LINE - 5 -BEF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166711 - 20 -1251.036620183522 - 11 -3448.29210116671 - 21 -1251.036620183522 - 0 -LINE - 5 -BF0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166711 - 20 -1251.186620183522 - 11 -3448.29210116671 - 21 -1251.186620183522 - 0 -LINE - 5 -BF1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166711 - 20 -1251.336620183522 - 11 -3448.29210116671 - 21 -1251.336620183522 - 0 -LWPOLYLINE - 5 -BF2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 31 - 70 - 0 - 43 -0 - 10 -3442.992101166711 - 20 -1248.636620183537 - 10 -3442.992101166711 - 20 -1248.686620183537 - 10 -3443.292101166711 - 20 -1248.686620183537 - 10 -3443.292101166711 - 20 -1248.836620183537 - 10 -3443.592101166711 - 20 -1248.836620183537 - 10 -3443.592101166711 - 20 -1248.986620183537 - 10 -3443.89210116671 - 20 -1248.986620183537 - 10 -3443.89210116671 - 20 -1249.136620183537 - 10 -3444.192101166712 - 20 -1249.136620183537 - 10 -3444.192101166712 - 20 -1249.286620183537 - 10 -3444.492101166711 - 20 -1249.286620183537 - 10 -3444.492101166711 - 20 -1249.436620183537 - 10 -3444.792101166711 - 20 -1249.436620183537 - 10 -3444.792101166711 - 20 -1249.586620183537 - 10 -3445.092101166711 - 20 -1249.586620183537 - 10 -3445.092101166711 - 20 -1249.736620183538 - 10 -3445.392101166712 - 20 -1249.736620183538 - 10 -3445.392101166712 - 20 -1249.886620183521 - 10 -3445.692101166712 - 20 -1249.886620183521 - 10 -3445.692101166712 - 20 -1250.036620183522 - 10 -3445.992101166712 - 20 -1250.036620183522 - 10 -3445.992101166712 - 20 -1250.186620183522 - 10 -3446.292101166712 - 20 -1250.186620183522 - 10 -3446.292101166712 - 20 -1250.336620183522 - 10 -3446.592101166713 - 20 -1250.336620183522 - 10 -3446.592101166713 - 20 -1250.486620183522 - 10 -3446.892101166714 - 20 -1250.486620183522 - 10 -3446.892101166714 - 20 -1250.636620183522 - 10 -3447.192101166713 - 20 -1250.636620183522 - 10 -3447.192101166713 - 20 -1250.786620183522 - 10 -3448.29210116671 - 20 -1250.786620183522 - 0 -LWPOLYLINE - 5 -BF3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 19 - 70 - 0 - 43 -0 - 10 -3447.092101166711 - 20 -1251.336620183522 - 10 -3447.092101166711 - 20 -1251.486620183522 - 10 -3446.79210116671 - 20 -1251.486620183522 - 10 -3446.79210116671 - 20 -1251.636620183522 - 10 -3446.49210116671 - 20 -1251.636620183522 - 10 -3446.49210116671 - 20 -1251.786620183523 - 10 -3446.19210116671 - 20 -1251.786620183523 - 10 -3446.19210116671 - 20 -1251.936620183523 - 10 -3445.89210116671 - 20 -1251.936620183523 - 10 -3445.89210116671 - 20 -1252.086620183523 - 10 -3445.59210116671 - 20 -1252.086620183523 - 10 -3445.59210116671 - 20 -1252.236620183523 - 10 -3445.292101166709 - 20 -1252.236620183523 - 10 -3445.292101166709 - 20 -1252.386620183523 - 10 -3444.99210116671 - 20 -1252.386620183523 - 10 -3444.99210116671 - 20 -1252.536620183523 - 10 -3444.692101166709 - 20 -1252.536620183523 - 10 -3444.692101166709 - 20 -1252.686620183507 - 10 -3444.392101166709 - 20 -1252.686620183507 - 0 -LWPOLYLINE - 5 -BF4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 20 - 70 - 0 - 43 -0 - 10 -3446.99210116671 - 20 -1251.336620183522 - 10 -3446.99210116671 - 20 -1251.386620183522 - 10 -3446.692101166711 - 20 -1251.386620183522 - 10 -3446.692101166711 - 20 -1251.536620183523 - 10 -3446.39210116671 - 20 -1251.536620183523 - 10 -3446.39210116671 - 20 -1251.686620183523 - 10 -3446.092101166711 - 20 -1251.686620183523 - 10 -3446.092101166711 - 20 -1251.836620183523 - 10 -3445.79210116671 - 20 -1251.836620183523 - 10 -3445.79210116671 - 20 -1251.986620183523 - 10 -3445.49210116671 - 20 -1251.986620183523 - 10 -3445.49210116671 - 20 -1252.136620183523 - 10 -3445.192101166711 - 20 -1252.136620183523 - 10 -3445.192101166711 - 20 -1252.286620183523 - 10 -3444.89210116671 - 20 -1252.286620183523 - 10 -3444.89210116671 - 20 -1252.436620183523 - 10 -3444.592101166711 - 20 -1252.436620183523 - 10 -3444.592101166711 - 20 -1252.586620183507 - 10 -3444.292101166709 - 20 -1252.586620183507 - 10 -3444.292101166709 - 20 -1252.586620183549 - 0 -LWPOLYLINE - 5 -BF5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3447.092101166756 - 20 -1251.336620183522 - 10 -3447.092101166756 - 20 -1251.236620183522 - 10 -3446.99210116671 - 20 -1251.23662018352 - 10 -3446.99210116671 - 20 -1251.336620183522 - 0 -LWPOLYLINE - 5 -BF6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 30 - 70 - 0 - 43 -0 - 10 -3443.792101166711 - 20 -1252.686620183463 - 10 -3443.792101166711 - 20 -1252.686620183463 - 10 -3443.792101166711 - 20 -1252.836620183464 - 10 -3444.092101166711 - 20 -1252.836620183464 - 10 -3444.092101166711 - 20 -1252.986620183464 - 10 -3444.392101166711 - 20 -1252.986620183464 - 10 -3444.392101166711 - 20 -1253.136620183464 - 10 -3444.692101166711 - 20 -1253.136620183464 - 10 -3444.692101166711 - 20 -1253.286620183464 - 10 -3444.992101166711 - 20 -1253.286620183464 - 10 -3444.992101166711 - 20 -1253.436620183464 - 10 -3445.292101166713 - 20 -1253.436620183464 - 10 -3445.292101166713 - 20 -1253.586620183448 - 10 -3445.592101166712 - 20 -1253.586620183448 - 10 -3445.592101166712 - 20 -1253.736620183448 - 10 -3445.892101166712 - 20 -1253.736620183448 - 10 -3445.892101166712 - 20 -1253.886620183448 - 10 -3446.192101166712 - 20 -1253.886620183448 - 10 -3446.192101166712 - 20 -1254.036620183448 - 10 -3446.492101166712 - 20 -1254.036620183448 - 10 -3446.492101166712 - 20 -1254.186620183448 - 10 -3446.792101166713 - 20 -1254.186620183448 - 10 -3446.792101166713 - 20 -1254.336620183448 - 10 -3447.092101166712 - 20 -1254.336620183448 - 10 -3447.092101166712 - 20 -1254.486620183448 - 10 -3448.29210116671 - 20 -1254.486620183448 - 10 -3448.29210116671 - 20 -1254.486620183448 - 10 -3448.29210116671 - 20 -1254.486620183448 - 10 -3448.29210116671 - 20 -1254.486620183448 - 10 -3448.29210116671 - 20 -1254.486620183448 - 0 -LWPOLYLINE - 5 -BF7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 25 - 70 - 0 - 43 -0 - 10 -3443.89210116671 - 20 -1252.686620183463 - 10 -3443.89210116671 - 20 -1252.736620183464 - 10 -3444.192101166712 - 20 -1252.736620183464 - 10 -3444.192101166712 - 20 -1252.886620183464 - 10 -3444.492101166711 - 20 -1252.886620183464 - 10 -3444.492101166711 - 20 -1253.036620183464 - 10 -3444.792101166711 - 20 -1253.036620183464 - 10 -3444.792101166711 - 20 -1253.186620183464 - 10 -3445.092101166711 - 20 -1253.186620183464 - 10 -3445.092101166711 - 20 -1253.336620183464 - 10 -3445.392101166711 - 20 -1253.336620183464 - 10 -3445.392101166711 - 20 -1253.486620183448 - 10 -3445.692101166712 - 20 -1253.486620183448 - 10 -3445.692101166712 - 20 -1253.636620183448 - 10 -3445.992101166711 - 20 -1253.636620183448 - 10 -3445.992101166711 - 20 -1253.786620183448 - 10 -3446.292101166712 - 20 -1253.786620183448 - 10 -3446.292101166712 - 20 -1253.936620183448 - 10 -3446.592101166712 - 20 -1253.936620183448 - 10 -3446.592101166712 - 20 -1254.086620183448 - 10 -3446.892101166712 - 20 -1254.086620183448 - 10 -3446.892101166712 - 20 -1254.236620183448 - 10 -3447.192101166712 - 20 -1254.236620183448 - 10 -3447.192101166712 - 20 -1254.386620183449 - 10 -3448.29210116671 - 20 -1254.386620183449 - 0 -LINE - 5 -BF8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166711 - 20 -1254.486620183448 - 11 -3448.29210116671 - 21 -1254.486620183448 - 0 -LINE - 5 -BF9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166711 - 20 -1254.636620183449 - 11 -3448.29210116671 - 21 -1254.636620183449 - 0 -LINE - 5 -BFA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166711 - 20 -1254.786620183448 - 11 -3448.29210116671 - 21 -1254.786620183448 - 0 -LINE - 5 -BFB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166711 - 20 -1254.936620183449 - 11 -3448.29210116671 - 21 -1254.936620183449 - 0 -LWPOLYLINE - 5 -BFC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 19 - 70 - 0 - 43 -0 - 10 -3447.092101166711 - 20 -1254.936620183449 - 10 -3447.092101166711 - 20 -1255.086620183449 - 10 -3446.79210116671 - 20 -1255.086620183449 - 10 -3446.79210116671 - 20 -1255.236620183449 - 10 -3446.49210116671 - 20 -1255.236620183449 - 10 -3446.49210116671 - 20 -1255.386620183449 - 10 -3446.19210116671 - 20 -1255.386620183449 - 10 -3446.19210116671 - 20 -1255.536620183449 - 10 -3445.89210116671 - 20 -1255.536620183449 - 10 -3445.89210116671 - 20 -1255.686620183449 - 10 -3445.59210116671 - 20 -1255.686620183449 - 10 -3445.59210116671 - 20 -1255.836620183449 - 10 -3445.292101166709 - 20 -1255.836620183449 - 10 -3445.292101166709 - 20 -1255.986620183449 - 10 -3444.99210116671 - 20 -1255.986620183449 - 10 -3444.99210116671 - 20 -1256.13662018345 - 10 -3444.692101166709 - 20 -1256.13662018345 - 10 -3444.692101166709 - 20 -1256.286620183433 - 10 -3444.392101166709 - 20 -1256.286620183433 - 0 -LWPOLYLINE - 5 -BFD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 20 - 70 - 0 - 43 -0 - 10 -3446.99210116671 - 20 -1254.936620183449 - 10 -3446.99210116671 - 20 -1254.986620183449 - 10 -3446.692101166711 - 20 -1254.986620183449 - 10 -3446.692101166711 - 20 -1255.136620183449 - 10 -3446.39210116671 - 20 -1255.136620183449 - 10 -3446.39210116671 - 20 -1255.286620183449 - 10 -3446.092101166711 - 20 -1255.286620183449 - 10 -3446.092101166711 - 20 -1255.436620183449 - 10 -3445.79210116671 - 20 -1255.436620183449 - 10 -3445.79210116671 - 20 -1255.586620183449 - 10 -3445.49210116671 - 20 -1255.586620183449 - 10 -3445.49210116671 - 20 -1255.736620183449 - 10 -3445.192101166711 - 20 -1255.736620183449 - 10 -3445.192101166711 - 20 -1255.886620183449 - 10 -3444.89210116671 - 20 -1255.886620183449 - 10 -3444.89210116671 - 20 -1256.03662018345 - 10 -3444.592101166711 - 20 -1256.03662018345 - 10 -3444.592101166711 - 20 -1256.186620183522 - 10 -3444.292101166709 - 20 -1256.186620183433 - 10 -3444.292101166709 - 20 -1256.28662018339 - 0 -LWPOLYLINE - 5 -BFE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3447.092101166756 - 20 -1254.936620183449 - 10 -3447.092101166756 - 20 -1254.836620183449 - 10 -3446.99210116671 - 20 -1254.836620183447 - 10 -3446.99210116671 - 20 -1254.936620183449 - 0 -HATCH - 5 -BFF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 38 - 72 - 1 - 10 -3446.892101166712 - 20 -1246.886620183561 - 11 -3447.192101166712 - 21 -1246.886620183561 - 72 - 1 - 10 -3447.192101166712 - 20 -1246.886620183561 - 11 -3447.192101166712 - 21 -1247.036620183561 - 72 - 1 - 10 -3447.192101166712 - 20 -1247.036620183561 - 11 -3448.29210116671 - 21 -1247.036620183561 - 72 - 1 - 10 -3448.29210116671 - 20 -1247.036620183561 - 11 -3448.29210116671 - 21 -1247.13662018356 - 72 - 1 - 10 -3448.29210116671 - 20 -1247.13662018356 - 11 -3447.092101166712 - 21 -1247.13662018356 - 72 - 1 - 10 -3447.092101166712 - 20 -1247.13662018356 - 11 -3447.092101166712 - 21 -1246.986620183561 - 72 - 1 - 10 -3447.092101166712 - 20 -1246.986620183561 - 11 -3446.792101166713 - 21 -1246.986620183561 - 72 - 1 - 10 -3446.792101166713 - 20 -1246.986620183561 - 11 -3446.792101166713 - 21 -1246.836620183561 - 72 - 1 - 10 -3446.792101166713 - 20 -1246.836620183561 - 11 -3446.492101166712 - 21 -1246.836620183561 - 72 - 1 - 10 -3446.492101166712 - 20 -1246.836620183561 - 11 -3446.492101166712 - 21 -1246.68662018356 - 72 - 1 - 10 -3446.492101166712 - 20 -1246.68662018356 - 11 -3446.192101166712 - 21 -1246.68662018356 - 72 - 1 - 10 -3446.192101166712 - 20 -1246.68662018356 - 11 -3446.192101166712 - 21 -1246.53662018356 - 72 - 1 - 10 -3446.192101166712 - 20 -1246.53662018356 - 11 -3445.892101166712 - 21 -1246.53662018356 - 72 - 1 - 10 -3445.892101166712 - 20 -1246.53662018356 - 11 -3445.892101166712 - 21 -1246.38662018356 - 72 - 1 - 10 -3445.892101166712 - 20 -1246.38662018356 - 11 -3445.592101166711 - 21 -1246.38662018356 - 72 - 1 - 10 -3445.592101166711 - 20 -1246.38662018356 - 11 -3445.592101166711 - 21 -1246.23662018356 - 72 - 1 - 10 -3445.592101166711 - 20 -1246.23662018356 - 11 -3445.292101166711 - 21 -1246.23662018356 - 72 - 1 - 10 -3445.292101166711 - 20 -1246.23662018356 - 11 -3445.292101166711 - 21 -1246.08662018356 - 72 - 1 - 10 -3445.292101166711 - 20 -1246.08662018356 - 11 -3444.992101166711 - 21 -1246.08662018356 - 72 - 1 - 10 -3444.992101166711 - 20 -1246.08662018356 - 11 -3444.992101166711 - 21 -1245.93662018356 - 72 - 1 - 10 -3444.992101166711 - 20 -1245.93662018356 - 11 -3444.784366980695 - 21 -1245.93662018356 - 72 - 1 - 10 -3444.784366980695 - 20 -1245.93662018356 - 11 -3444.784366980695 - 21 -1245.78662018356 - 72 - 1 - 10 -3444.784366980695 - 20 -1245.78662018356 - 11 -3444.792101166711 - 21 -1245.78662018356 - 72 - 1 - 10 -3444.792101166711 - 20 -1245.78662018356 - 11 -3444.792101166711 - 21 -1245.83662018356 - 72 - 1 - 10 -3444.792101166711 - 20 -1245.83662018356 - 11 -3445.092101166711 - 21 -1245.83662018356 - 72 - 1 - 10 -3445.092101166711 - 20 -1245.83662018356 - 11 -3445.092101166711 - 21 -1245.98662018356 - 72 - 1 - 10 -3445.092101166711 - 20 -1245.98662018356 - 11 -3445.392101166711 - 21 -1245.98662018356 - 72 - 1 - 10 -3445.392101166711 - 20 -1245.98662018356 - 11 -3445.392101166711 - 21 -1246.13662018356 - 72 - 1 - 10 -3445.392101166711 - 20 -1246.13662018356 - 11 -3445.692101166712 - 21 -1246.13662018356 - 72 - 1 - 10 -3445.692101166712 - 20 -1246.13662018356 - 11 -3445.692101166712 - 21 -1246.28662018356 - 72 - 1 - 10 -3445.692101166712 - 20 -1246.28662018356 - 11 -3445.992101166711 - 21 -1246.28662018356 - 72 - 1 - 10 -3445.992101166711 - 20 -1246.28662018356 - 11 -3445.992101166711 - 21 -1246.43662018356 - 72 - 1 - 10 -3445.992101166711 - 20 -1246.43662018356 - 11 -3446.292101166712 - 21 -1246.43662018356 - 72 - 1 - 10 -3446.292101166712 - 20 -1246.43662018356 - 11 -3446.292101166712 - 21 -1246.58662018356 - 72 - 1 - 10 -3446.292101166712 - 20 -1246.58662018356 - 11 -3446.592101166711 - 21 -1246.58662018356 - 72 - 1 - 10 -3446.592101166711 - 20 -1246.58662018356 - 11 -3446.592101166711 - 21 -1246.736620183561 - 72 - 1 - 10 -3446.592101166711 - 20 -1246.736620183561 - 11 -3446.892101166712 - 21 -1246.736620183561 - 72 - 1 - 10 -3446.892101166712 - 20 -1246.736620183561 - 11 -3446.892101166712 - 21 -1246.886620183561 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -C00 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 38 - 72 - 1 - 10 -3448.29210116671 - 20 -1254.486620183448 - 11 -3447.092101166712 - 21 -1254.486620183448 - 72 - 1 - 10 -3447.092101166712 - 20 -1254.486620183448 - 11 -3447.092101166712 - 21 -1254.336620183448 - 72 - 1 - 10 -3447.092101166712 - 20 -1254.336620183448 - 11 -3446.792101166713 - 21 -1254.336620183448 - 72 - 1 - 10 -3446.792101166713 - 20 -1254.336620183448 - 11 -3446.792101166713 - 21 -1254.186620183448 - 72 - 1 - 10 -3446.792101166713 - 20 -1254.186620183448 - 11 -3446.492101166712 - 21 -1254.186620183448 - 72 - 1 - 10 -3446.492101166712 - 20 -1254.186620183448 - 11 -3446.492101166712 - 21 -1254.036620183448 - 72 - 1 - 10 -3446.492101166712 - 20 -1254.036620183448 - 11 -3446.192101166712 - 21 -1254.036620183448 - 72 - 1 - 10 -3446.192101166712 - 20 -1254.036620183448 - 11 -3446.192101166712 - 21 -1253.886620183448 - 72 - 1 - 10 -3446.192101166712 - 20 -1253.886620183448 - 11 -3445.892101166712 - 21 -1253.886620183448 - 72 - 1 - 10 -3445.892101166712 - 20 -1253.886620183448 - 11 -3445.892101166712 - 21 -1253.736620183448 - 72 - 1 - 10 -3445.892101166712 - 20 -1253.736620183448 - 11 -3445.592101166712 - 21 -1253.736620183448 - 72 - 1 - 10 -3445.592101166712 - 20 -1253.736620183448 - 11 -3445.592101166712 - 21 -1253.586620183448 - 72 - 1 - 10 -3445.592101166712 - 20 -1253.586620183448 - 11 -3445.292101166713 - 21 -1253.586620183448 - 72 - 1 - 10 -3445.292101166713 - 20 -1253.586620183448 - 11 -3445.292101166713 - 21 -1253.436620183464 - 72 - 1 - 10 -3445.292101166713 - 20 -1253.436620183464 - 11 -3444.992101166711 - 21 -1253.436620183464 - 72 - 1 - 10 -3444.992101166711 - 20 -1253.436620183464 - 11 -3444.992101166711 - 21 -1253.286620183464 - 72 - 1 - 10 -3444.992101166711 - 20 -1253.286620183464 - 11 -3444.784366980695 - 21 -1253.286620183464 - 72 - 1 - 10 -3444.784366980695 - 20 -1253.286620183464 - 11 -3444.784366980695 - 21 -1253.036620183464 - 72 - 1 - 10 -3444.784366980695 - 20 -1253.036620183464 - 11 -3444.792101166711 - 21 -1253.036620183464 - 72 - 1 - 10 -3444.792101166711 - 20 -1253.036620183464 - 11 -3444.792101166711 - 21 -1253.186620183464 - 72 - 1 - 10 -3444.792101166711 - 20 -1253.186620183464 - 11 -3445.092101166711 - 21 -1253.186620183464 - 72 - 1 - 10 -3445.092101166711 - 20 -1253.186620183464 - 11 -3445.092101166711 - 21 -1253.336620183464 - 72 - 1 - 10 -3445.092101166711 - 20 -1253.336620183464 - 11 -3445.392101166711 - 21 -1253.336620183464 - 72 - 1 - 10 -3445.392101166711 - 20 -1253.336620183464 - 11 -3445.392101166711 - 21 -1253.486620183448 - 72 - 1 - 10 -3445.392101166711 - 20 -1253.486620183448 - 11 -3445.692101166712 - 21 -1253.486620183448 - 72 - 1 - 10 -3445.692101166712 - 20 -1253.486620183448 - 11 -3445.692101166712 - 21 -1253.636620183448 - 72 - 1 - 10 -3445.692101166712 - 20 -1253.636620183448 - 11 -3445.992101166711 - 21 -1253.636620183448 - 72 - 1 - 10 -3445.992101166711 - 20 -1253.636620183448 - 11 -3445.992101166711 - 21 -1253.786620183448 - 72 - 1 - 10 -3445.992101166711 - 20 -1253.786620183448 - 11 -3446.292101166712 - 21 -1253.786620183448 - 72 - 1 - 10 -3446.292101166712 - 20 -1253.786620183448 - 11 -3446.292101166712 - 21 -1253.936620183448 - 72 - 1 - 10 -3446.292101166712 - 20 -1253.936620183448 - 11 -3446.592101166712 - 21 -1253.936620183448 - 72 - 1 - 10 -3446.592101166712 - 20 -1253.936620183448 - 11 -3446.592101166712 - 21 -1254.086620183448 - 72 - 1 - 10 -3446.592101166712 - 20 -1254.086620183448 - 11 -3446.892101166712 - 21 -1254.086620183448 - 72 - 1 - 10 -3446.892101166712 - 20 -1254.086620183448 - 11 -3446.892101166712 - 21 -1254.236620183448 - 72 - 1 - 10 -3446.892101166712 - 20 -1254.236620183448 - 11 -3447.192101166712 - 21 -1254.236620183448 - 72 - 1 - 10 -3447.192101166712 - 20 -1254.236620183448 - 11 -3447.192101166712 - 21 -1254.386620183449 - 72 - 1 - 10 -3447.192101166712 - 20 -1254.386620183449 - 11 -3448.29210116671 - 21 -1254.386620183449 - 72 - 1 - 10 -3448.29210116671 - 20 -1254.386620183449 - 11 -3448.29210116671 - 21 -1254.486620183448 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -C01 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 62 - 72 - 1 - 10 -3448.29210116671 - 20 -1250.886620183522 - 11 -3447.092101166714 - 21 -1250.886620183522 - 72 - 1 - 10 -3447.092101166714 - 20 -1250.886620183522 - 11 -3447.092101166714 - 21 -1250.736620183522 - 72 - 1 - 10 -3447.092101166714 - 20 -1250.736620183522 - 11 -3446.792101166713 - 21 -1250.736620183522 - 72 - 1 - 10 -3446.792101166713 - 20 -1250.736620183522 - 11 -3446.792101166713 - 21 -1250.586620183522 - 72 - 1 - 10 -3446.792101166713 - 20 -1250.586620183522 - 11 -3446.492101166712 - 21 -1250.586620183522 - 72 - 1 - 10 -3446.492101166712 - 20 -1250.586620183522 - 11 -3446.492101166712 - 21 -1250.436620183522 - 72 - 1 - 10 -3446.492101166712 - 20 -1250.436620183522 - 11 -3446.192101166712 - 21 -1250.436620183522 - 72 - 1 - 10 -3446.192101166712 - 20 -1250.436620183522 - 11 -3446.192101166712 - 21 -1250.286620183522 - 72 - 1 - 10 -3446.192101166712 - 20 -1250.286620183522 - 11 -3445.892101166712 - 21 -1250.286620183522 - 72 - 1 - 10 -3445.892101166712 - 20 -1250.286620183522 - 11 -3445.892101166712 - 21 -1250.136620183522 - 72 - 1 - 10 -3445.892101166712 - 20 -1250.136620183522 - 11 -3445.592101166712 - 21 -1250.136620183522 - 72 - 1 - 10 -3445.592101166712 - 20 -1250.136620183522 - 11 -3445.592101166712 - 21 -1249.986620183521 - 72 - 1 - 10 -3445.592101166712 - 20 -1249.986620183521 - 11 -3445.292101166713 - 21 -1249.986620183521 - 72 - 1 - 10 -3445.292101166713 - 20 -1249.986620183521 - 11 -3445.292101166713 - 21 -1249.836620183538 - 72 - 1 - 10 -3445.292101166713 - 20 -1249.836620183538 - 11 -3444.992101166711 - 21 -1249.836620183538 - 72 - 1 - 10 -3444.992101166711 - 20 -1249.836620183538 - 11 -3444.992101166711 - 21 -1249.686620183537 - 72 - 1 - 10 -3444.992101166711 - 20 -1249.686620183537 - 11 -3444.692101166712 - 21 -1249.686620183537 - 72 - 1 - 10 -3444.692101166712 - 20 -1249.686620183537 - 11 -3444.692101166712 - 21 -1249.536620183537 - 72 - 1 - 10 -3444.692101166712 - 20 -1249.536620183537 - 11 -3444.392101166712 - 21 -1249.536620183537 - 72 - 1 - 10 -3444.392101166712 - 20 -1249.536620183537 - 11 -3444.392101166712 - 21 -1249.386620183537 - 72 - 1 - 10 -3444.392101166712 - 20 -1249.386620183537 - 11 -3444.092101166711 - 21 -1249.386620183537 - 72 - 1 - 10 -3444.092101166711 - 20 -1249.386620183537 - 11 -3444.092101166711 - 21 -1249.236620183537 - 72 - 1 - 10 -3444.092101166711 - 20 -1249.236620183537 - 11 -3443.792101166711 - 21 -1249.236620183537 - 72 - 1 - 10 -3443.792101166711 - 20 -1249.236620183537 - 11 -3443.792101166711 - 21 -1249.086620183537 - 72 - 1 - 10 -3443.792101166711 - 20 -1249.086620183537 - 11 -3443.492101166711 - 21 -1249.086620183537 - 72 - 1 - 10 -3443.492101166711 - 20 -1249.086620183537 - 11 -3443.492101166711 - 21 -1248.936620183537 - 72 - 1 - 10 -3443.492101166711 - 20 -1248.936620183537 - 11 -3443.192101166711 - 21 -1248.936620183537 - 72 - 1 - 10 -3443.192101166711 - 20 -1248.936620183537 - 11 -3443.192101166711 - 21 -1248.786620183537 - 72 - 1 - 10 -3443.192101166711 - 20 -1248.786620183537 - 11 -3442.892101166711 - 21 -1248.786620183537 - 72 - 1 - 10 -3442.892101166711 - 20 -1248.786620183537 - 11 -3442.892101166711 - 21 -1248.636620183537 - 72 - 1 - 10 -3442.892101166711 - 20 -1248.636620183537 - 11 -3442.992101166711 - 21 -1248.636620183537 - 72 - 1 - 10 -3442.992101166711 - 20 -1248.636620183537 - 11 -3442.992101166711 - 21 -1248.686620183537 - 72 - 1 - 10 -3442.992101166711 - 20 -1248.686620183537 - 11 -3443.292101166711 - 21 -1248.686620183537 - 72 - 1 - 10 -3443.292101166711 - 20 -1248.686620183537 - 11 -3443.292101166711 - 21 -1248.836620183537 - 72 - 1 - 10 -3443.292101166711 - 20 -1248.836620183537 - 11 -3443.592101166711 - 21 -1248.836620183537 - 72 - 1 - 10 -3443.592101166711 - 20 -1248.836620183537 - 11 -3443.592101166711 - 21 -1248.986620183537 - 72 - 1 - 10 -3443.592101166711 - 20 -1248.986620183537 - 11 -3443.89210116671 - 21 -1248.986620183537 - 72 - 1 - 10 -3443.89210116671 - 20 -1248.986620183537 - 11 -3443.89210116671 - 21 -1249.136620183537 - 72 - 1 - 10 -3443.89210116671 - 20 -1249.136620183537 - 11 -3444.192101166712 - 21 -1249.136620183537 - 72 - 1 - 10 -3444.192101166712 - 20 -1249.136620183537 - 11 -3444.192101166712 - 21 -1249.286620183537 - 72 - 1 - 10 -3444.192101166712 - 20 -1249.286620183537 - 11 -3444.492101166711 - 21 -1249.286620183537 - 72 - 1 - 10 -3444.492101166711 - 20 -1249.286620183537 - 11 -3444.492101166711 - 21 -1249.436620183537 - 72 - 1 - 10 -3444.492101166711 - 20 -1249.436620183537 - 11 -3444.792101166711 - 21 -1249.436620183537 - 72 - 1 - 10 -3444.792101166711 - 20 -1249.436620183537 - 11 -3444.792101166711 - 21 -1249.586620183537 - 72 - 1 - 10 -3444.792101166711 - 20 -1249.586620183537 - 11 -3445.092101166711 - 21 -1249.586620183537 - 72 - 1 - 10 -3445.092101166711 - 20 -1249.586620183537 - 11 -3445.092101166711 - 21 -1249.736620183538 - 72 - 1 - 10 -3445.092101166711 - 20 -1249.736620183538 - 11 -3445.392101166712 - 21 -1249.736620183538 - 72 - 1 - 10 -3445.392101166712 - 20 -1249.736620183538 - 11 -3445.392101166712 - 21 -1249.886620183521 - 72 - 1 - 10 -3445.392101166712 - 20 -1249.886620183521 - 11 -3445.692101166712 - 21 -1249.886620183521 - 72 - 1 - 10 -3445.692101166712 - 20 -1249.886620183521 - 11 -3445.692101166712 - 21 -1250.036620183522 - 72 - 1 - 10 -3445.692101166712 - 20 -1250.036620183522 - 11 -3445.992101166712 - 21 -1250.036620183522 - 72 - 1 - 10 -3445.992101166712 - 20 -1250.036620183522 - 11 -3445.992101166712 - 21 -1250.186620183522 - 72 - 1 - 10 -3445.992101166712 - 20 -1250.186620183522 - 11 -3446.292101166712 - 21 -1250.186620183522 - 72 - 1 - 10 -3446.292101166712 - 20 -1250.186620183522 - 11 -3446.292101166712 - 21 -1250.336620183522 - 72 - 1 - 10 -3446.292101166712 - 20 -1250.336620183522 - 11 -3446.592101166713 - 21 -1250.336620183522 - 72 - 1 - 10 -3446.592101166713 - 20 -1250.336620183522 - 11 -3446.592101166713 - 21 -1250.486620183522 - 72 - 1 - 10 -3446.592101166713 - 20 -1250.486620183522 - 11 -3446.892101166714 - 21 -1250.486620183522 - 72 - 1 - 10 -3446.892101166714 - 20 -1250.486620183522 - 11 -3446.892101166714 - 21 -1250.636620183522 - 72 - 1 - 10 -3446.892101166714 - 20 -1250.636620183522 - 11 -3447.192101166713 - 21 -1250.636620183522 - 72 - 1 - 10 -3447.192101166713 - 20 -1250.636620183522 - 11 -3447.192101166713 - 21 -1250.786620183522 - 72 - 1 - 10 -3447.192101166713 - 20 -1250.786620183522 - 11 -3448.29210116671 - 21 -1250.786620183522 - 72 - 1 - 10 -3448.29210116671 - 20 -1250.786620183522 - 11 -3448.29210116671 - 21 -1250.886620183522 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -C02 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 9 - 72 - 1 - 10 -3444.192101166712 - 20 -1252.886620183464 - 11 -3444.192101166716 - 21 -1252.986620183464 - 72 - 1 - 10 -3444.192101166716 - 20 -1252.986620183464 - 11 -3444.092101166711 - 21 -1252.986620183464 - 72 - 1 - 10 -3444.092101166711 - 20 -1252.986620183464 - 11 -3444.092101166711 - 21 -1252.836620183464 - 72 - 1 - 10 -3444.092101166711 - 20 -1252.836620183464 - 11 -3443.792101166711 - 21 -1252.836620183464 - 72 - 1 - 10 -3443.792101166711 - 20 -1252.836620183464 - 11 -3443.792101166711 - 21 -1252.686620183463 - 72 - 1 - 10 -3443.792101166711 - 20 -1252.686620183463 - 11 -3443.89210116671 - 21 -1252.686620183463 - 72 - 1 - 10 -3443.89210116671 - 20 -1252.686620183463 - 11 -3443.89210116671 - 21 -1252.736620183464 - 72 - 1 - 10 -3443.89210116671 - 20 -1252.736620183464 - 11 -3444.192101166712 - 21 -1252.736620183464 - 72 - 1 - 10 -3444.192101166712 - 20 -1252.736620183464 - 11 -3444.192101166712 - 21 -1252.886620183464 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -C03 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 6 - 72 - 1 - 10 -3444.784366980695 - 20 -1253.286620183464 - 11 -3444.692101166711 - 21 -1253.286620183464 - 72 - 1 - 10 -3444.692101166711 - 20 -1253.286620183464 - 11 -3444.692101166711 - 21 -1253.136620183464 - 72 - 1 - 10 -3444.692101166711 - 20 -1253.136620183464 - 11 -3444.554366980713 - 21 -1253.136620183464 - 72 - 1 - 10 -3444.554366980713 - 20 -1253.136620183464 - 11 -3444.554366980713 - 21 -1253.036620183464 - 72 - 1 - 10 -3444.554366980713 - 20 -1253.036620183464 - 11 -3444.784366980695 - 21 -1253.036620183464 - 72 - 1 - 10 -3444.784366980695 - 20 -1253.036620183464 - 11 -3444.784366980695 - 21 -1253.286620183464 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -C04 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 8 - 72 - 1 - 10 -3444.492101166711 - 20 -1253.036620183464 - 11 -3444.554366980713 - 21 -1253.036620183464 - 72 - 1 - 10 -3444.554366980713 - 20 -1253.036620183464 - 11 -3444.554366980713 - 21 -1253.136620183464 - 72 - 1 - 10 -3444.554366980713 - 20 -1253.136620183464 - 11 -3444.392101166711 - 21 -1253.136620183464 - 72 - 1 - 10 -3444.392101166711 - 20 -1253.136620183464 - 11 -3444.392101166711 - 21 -1252.986620183464 - 72 - 1 - 10 -3444.392101166711 - 20 -1252.986620183464 - 11 -3444.192101166733 - 21 -1252.986620183464 - 72 - 1 - 10 -3444.192101166733 - 20 -1252.986620183464 - 11 -3444.192101166733 - 21 -1252.886620183464 - 72 - 1 - 10 -3444.192101166733 - 20 -1252.886620183464 - 11 -3444.492101166711 - 21 -1252.886620183464 - 72 - 1 - 10 -3444.492101166711 - 20 -1252.886620183464 - 11 -3444.492101166711 - 21 -1253.036620183464 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LINE - 5 -C05 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.29210116671 - 20 -1248.536620183537 - 11 -3431.59436698075 - 21 -1248.536620183537 - 0 -LWPOLYLINE - 5 -C06 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3434.344366980717 - 20 -1252.684620183551 - 10 -3444.692101166709 - 20 -1252.684620183551 - 10 -3444.692101166709 - 20 -1252.586798794548 - 10 -3434.344366980717 - 20 -1252.586798794548 - 0 -HATCH - 5 -C07 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.692101166709 - 20 -1252.686620183584 - 11 -3434.344366980717 - 21 -1252.686620183584 - 72 - 1 - 10 -3434.344366980717 - 20 -1252.686620183584 - 11 -3434.344366980717 - 21 -1252.586798794548 - 72 - 1 - 10 -3434.344366980717 - 20 -1252.586798794548 - 11 -3444.692101166709 - 21 -1252.586798794548 - 72 - 1 - 10 -3444.692101166709 - 20 -1252.586798794548 - 11 -3444.692101166709 - 21 -1252.686620183584 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -C08 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.592101166711 - 20 -1256.286620183557 - 11 -3434.344366980717 - 21 -1256.286620183557 - 72 - 1 - 10 -3434.344366980717 - 20 -1256.286620183557 - 11 -3434.344366980717 - 21 -1256.186620183522 - 72 - 1 - 10 -3434.344366980717 - 20 -1256.186620183522 - 11 -3444.592101166711 - 21 -1256.186620183522 - 72 - 1 - 10 -3444.592101166711 - 20 -1256.186620183522 - 11 -3444.592101166711 - 21 -1256.286620183557 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -C09 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3447.092101166756 - 20 -1251.336620183522 - 10 -3447.092101166756 - 20 -1250.886620183522 - 0 -LWPOLYLINE - 5 -C0A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3447.092101166756 - 20 -1254.936620183449 - 10 -3447.092101166711 - 20 -1254.486620183448 - 0 -LWPOLYLINE - 5 -C0B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.59210116671 - 20 -1259.789325424532 - 10 -3445.59210116671 - 20 -1255.836620183449 - 0 -LWPOLYLINE - 5 -C0C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.59210116671 - 20 -1255.586620183449 - 10 -3445.592101166712 - 20 -1253.586620183448 - 0 -LWPOLYLINE - 5 -C0D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.592101166712 - 20 -1253.486620183448 - 10 -3445.592101166712 - 20 -1252.086620183523 - 0 -LWPOLYLINE - 5 -C0E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.59210116671 - 20 -1251.986620183523 - 10 -3445.59210116671 - 20 -1249.986620183521 - 0 -LWPOLYLINE - 5 -C0F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3445.59210116671 - 20 -1249.886620183521 - 10 -3445.59210116671 - 20 -1248.636620183553 - 10 -3445.59210116671 - 20 -1248.336620183561 - 0 -LWPOLYLINE - 5 -C10 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.59210116671 - 20 -1248.236620183561 - 10 -3445.59210116671 - 20 -1246.23662018356 - 0 -LWPOLYLINE - 5 -C11 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.59210116671 - 20 -1246.13662018356 - 10 -3445.59210116671 - 20 -1245.78662018356 - 0 -LWPOLYLINE - 5 -C12 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.10610116671 - 20 -1259.789325424532 - 10 -3445.10610116671 - 20 -1255.986620183449 - 0 -LWPOLYLINE - 5 -C13 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.10610116671 - 20 -1255.886620183449 - 10 -3445.106101166711 - 20 -1253.436620183464 - 0 -LWPOLYLINE - 5 -C14 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.10610116671 - 20 -1252.286620183523 - 10 -3445.10610116671 - 20 -1249.986620183521 - 0 -LWPOLYLINE - 5 -C15 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.106101166711 - 20 -1253.336620183464 - 10 -3445.106101166711 - 20 -1252.386620183523 - 0 -LWPOLYLINE - 5 -C16 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3445.10610116671 - 20 -1249.886620183521 - 10 -3445.10610116671 - 20 -1248.636620183553 - 10 -3445.10610116671 - 20 -1248.336620183561 - 0 -LWPOLYLINE - 5 -C17 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.10610116671 - 20 -1248.236620183561 - 10 -3445.10610116671 - 20 -1246.23662018356 - 0 -MTEXT - 5 -C18 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3447.212417758449 - 20 -1252.032848458575 - 30 -0 - 40 -0.1 - 41 -0.6000000000000109 - 71 - 1 - 72 - 5 - 1 -rise=0.15\Ptread=0.3 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C19 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3447.212417758449 - 20 -1255.619126371433 - 30 -0 - 40 -0.1 - 41 -0.6000000000000109 - 71 - 1 - 72 - 5 - 1 -rise=0.15\Ptread=0.3 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C1A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3375.995849914151 - 20 -1247.328727787206 - 30 -0 - 40 -0.4900000000000003 - 41 -4.831944444444448 - 71 - 1 - 72 - 5 - 1 -OPEN TERRACE - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LINE - 5 -C1B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3466.390140816788 - 20 -1248.636620183537 - 11 -3466.390140816788 - 21 -1248.186620183525 - 0 -LINE - 5 -C1C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3466.390140816788 - 20 -1248.569042596211 - 11 -3467.590140816788 - 21 -1248.569042596211 - 0 -LINE - 5 -C1D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3466.390140816788 - 20 -1248.411620183531 - 11 -3467.590140816788 - 21 -1248.411620183531 - 0 -LINE - 5 -C1E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3466.390140816788 - 20 -1248.272427580647 - 11 -3467.590140816788 - 21 -1248.272427580647 - 0 -LWPOLYLINE - 5 -C1F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3376.062164167408 - 20 -1242.722369963012 - 10 -3377.575810118579 - 20 -1242.722369963012 - 10 -3377.575810118579 - 20 -1245.238323131401 - 10 -3383.809634535341 - 20 -1245.238323131401 - 0 -LWPOLYLINE - 5 -C20 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3372.492164165247 - 20 -1255.550104161259 - 10 -3374.252164165259 - 20 -1255.550104161433 - 0 -MTEXT - 5 -C21 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3354.521414246792 - 20 -1243.408046316952 - 30 -0 - 40 -0.1 - 41 -0.6000000000000109 - 71 - 1 - 72 - 5 - 1 -rise=0.15\Ptread=0.3 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C22 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3318.268788193533 - 20 -1243.415108964659 - 30 -0 - 40 -0.1 - 41 -0.6000000000000109 - 71 - 1 - 72 - 5 - 1 -rise=0.15\Ptread=0.3 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C23 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3301.394087663785 - 20 -1243.407997752577 - 30 -0 - 40 -0.1 - 41 -0.6000000000000109 - 71 - 1 - 72 - 5 - 1 -rise=0.15\Ptread=0.3 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C24 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3283.871208875372 - 20 -1243.293785905065 - 30 -0 - 40 -0.1 - 41 -0.6000000000000109 - 71 - 1 - 72 - 5 - 1 -rise=0.15\Ptread=0.3 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C25 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3299.13600457971 - 20 -1258.982525219176 - 30 -0 - 40 -0.1 - 41 -0.6777777777777824 - 71 - 1 - 72 - 5 - 1 -rise=.176\Ptread=0.20 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883538 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C26 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3316.331542286111 - 20 -1258.941173809992 - 30 -0 - 40 -0.1 - 41 -0.6777777777777824 - 71 - 1 - 72 - 5 - 1 -rise=0.164\Ptread=0.20 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883538 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C27 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3352.588222598622 - 20 -1258.954535950939 - 30 -0 - 40 -0.1 - 41 -0.6777777777777824 - 71 - 1 - 72 - 5 - 1 -rise=0.164\Ptread=0.20 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883538 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C28 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3705.993289694646 - 20 -1109.033869380241 - 30 -0 - 40 -0.34 - 41 -4.004444300282983 - 71 - 5 - 72 - 1 - 1 -\W0.8;\C7;ACCESS - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -HATCH - 5 -C29 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.48983535287 - 20 -1254.036620183495 - 11 -3448.48983535287 - 21 -1254.136620183471 - 72 - 1 - 10 -3448.48983535287 - 20 -1254.136620183471 - 11 -3448.29210116671 - 21 -1254.136620183471 - 72 - 1 - 10 -3448.29210116671 - 20 -1254.136620183471 - 11 -3448.29210116671 - 21 -1254.036620183495 - 72 - 1 - 10 -3448.29210116671 - 20 -1254.036620183495 - 11 -3448.48983535287 - 21 -1254.036620183495 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -C2A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.48983535287 - 20 -1254.136620183471 - 11 -3448.48983535287 - 21 -1254.486620183448 - 72 - 1 - 10 -3448.48983535287 - 20 -1254.486620183448 - 11 -3448.29210116671 - 21 -1254.486620183448 - 72 - 1 - 10 -3448.29210116671 - 20 -1254.486620183448 - 11 -3448.29210116671 - 21 -1254.136620183471 - 72 - 1 - 10 -3448.29210116671 - 20 -1254.136620183471 - 11 -3448.48983535287 - 21 -1254.136620183471 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -C2B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.48983535287 - 20 -1250.436620183569 - 11 -3448.48983535287 - 21 -1250.536620183545 - 72 - 1 - 10 -3448.48983535287 - 20 -1250.536620183545 - 11 -3448.29210116671 - 21 -1250.536620183545 - 72 - 1 - 10 -3448.29210116671 - 20 -1250.536620183545 - 11 -3448.29210116671 - 21 -1250.436620183569 - 72 - 1 - 10 -3448.29210116671 - 20 -1250.436620183569 - 11 -3448.48983535287 - 21 -1250.436620183569 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -C2C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.48983535287 - 20 -1250.536620183545 - 11 -3448.48983535287 - 21 -1250.886620183522 - 72 - 1 - 10 -3448.48983535287 - 20 -1250.886620183522 - 11 -3448.29210116671 - 21 -1250.886620183522 - 72 - 1 - 10 -3448.29210116671 - 20 -1250.886620183522 - 11 -3448.29210116671 - 21 -1250.536620183545 - 72 - 1 - 10 -3448.29210116671 - 20 -1250.536620183545 - 11 -3448.48983535287 - 21 -1250.536620183545 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -C2D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1243.312547942015 - 10 -3307.031947087264 - 20 -1243.312547942015 - 0 -LWPOLYLINE - 5 -C2E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1243.20135832997 - 10 -3307.031947087264 - 20 -1243.20135832997 - 0 -LWPOLYLINE - 5 -C2F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084847 - 20 -1243.090168717925 - 10 -3307.031947086011 - 20 -1243.090168717925 - 0 -LWPOLYLINE - 5 -C30 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084757 - 20 -1242.97897910588 - 10 -3307.031947085923 - 20 -1242.97897910588 - 0 -LWPOLYLINE - 5 -C31 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084668 - 20 -1242.867789493836 - 10 -3307.031947085833 - 20 -1242.867789493836 - 0 -LWPOLYLINE - 5 -C32 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084579 - 20 -1242.756599881791 - 10 -3307.031947085743 - 20 -1242.756599881791 - 0 -LWPOLYLINE - 5 -C33 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.83194708449 - 20 -1242.645410269746 - 10 -3307.031947085655 - 20 -1242.645410269746 - 0 -LWPOLYLINE - 5 -C34 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084401 - 20 -1242.534220657701 - 10 -3307.031947085565 - 20 -1242.534220657701 - 0 -LWPOLYLINE - 5 -C35 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084313 - 20 -1242.423031045656 - 10 -3307.031947085476 - 20 -1242.423031045656 - 0 -LWPOLYLINE - 5 -C36 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084223 - 20 -1242.311841433611 - 10 -3307.031947085387 - 20 -1242.311841433611 - 0 -LWPOLYLINE - 5 -C37 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084133 - 20 -1242.200651821566 - 10 -3307.031947085298 - 20 -1242.200651821566 - 0 -LWPOLYLINE - 5 -C38 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084044 - 20 -1242.089462209521 - 10 -3307.031947085209 - 20 -1242.089462209521 - 0 -LWPOLYLINE - 5 -C39 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947083955 - 20 -1241.978272597477 - 10 -3307.03194708512 - 20 -1241.978272597477 - 0 -LWPOLYLINE - 5 -C3A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947083866 - 20 -1241.867082985432 - 10 -3307.031947085032 - 20 -1241.867082985432 - 0 -LWPOLYLINE - 5 -C3B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947083777 - 20 -1241.755893373387 - 10 -3307.031947084941 - 20 -1241.755893373387 - 0 -LWPOLYLINE - 5 -C3C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947083688 - 20 -1241.644703761342 - 10 -3307.0319470861 - 20 -1241.644703761342 - 0 -LWPOLYLINE - 5 -C3D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1241.615544322921 - 10 -3307.0319470861 - 20 -1241.615544322921 - 0 -LWPOLYLINE - 5 -C3E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1241.573887651951 - 10 -3307.0319470861 - 20 -1241.573887651951 - 0 -LWPOLYLINE - 5 -C3F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1241.546811856485 - 10 -3307.0319470861 - 20 -1241.546811856485 - 0 -LWPOLYLINE - 5 -C40 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1241.53223098098 - 10 -3307.0319470861 - 20 -1241.53223098098 - 0 -LWPOLYLINE - 5 -C41 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1241.51140380179 - 10 -3307.0319470861 - 20 -1241.51140380179 - 0 -LWPOLYLINE - 5 -C42 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1241.47807707746 - 10 -3307.0319470861 - 20 -1241.47807707746 - 0 -LWPOLYLINE - 5 -C43 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1241.461414871589 - 10 -3307.0319470861 - 20 -1241.461414871589 - 0 -LWPOLYLINE - 5 -C44 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.821525894156 - 20 -1241.442669022764 - 10 -3307.0319470861 - 20 -1241.442669022764 - 0 -LWPOLYLINE - 5 -C45 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.821525894156 - 20 -1241.403095994748 - 10 -3307.0319470861 - 20 -1241.403095994748 - 0 -LWPOLYLINE - 5 -C46 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.825692467923 - 20 -1241.365606609687 - 10 -3307.0319470861 - 20 -1241.365606609687 - 0 -LWPOLYLINE - 5 -C47 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.825692467923 - 20 -1241.359357993413 - 10 -3307.0319470861 - 20 -1241.359357993413 - 0 -LWPOLYLINE - 5 -C48 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.825692467923 - 20 -1241.334363528312 - 10 -3307.0319470861 - 20 -1241.334363528312 - 0 -LWPOLYLINE - 5 -C49 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.827775754806 - 20 -1241.313534036532 - 10 -3307.0319470861 - 20 -1241.313534036532 - 0 -LWPOLYLINE - 5 -C4A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.827775754806 - 20 -1241.298955473617 - 10 -3307.0319470861 - 20 -1241.298955473617 - 0 -LWPOLYLINE - 5 -C4B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084936 - 20 -1241.263547418921 - 10 -3307.0319470861 - 20 -1241.263547418921 - 0 -LWPOLYLINE - 5 -C4C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1241.280209624791 - 10 -3307.0319470861 - 20 -1241.280209624791 - 0 -LWPOLYLINE - 5 -C4D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084936 - 20 -1241.234387980501 - 10 -3307.0319470861 - 20 -1241.234387980501 - 0 -LWPOLYLINE - 5 -C4E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.82224410493 - 20 -1241.386685861111 - 10 -3307.0319470861 - 20 -1241.386685861111 - 0 -LWPOLYLINE - 5 -C4F -100 -AcDbEntity - 8 -BLK_1_DA_RAMP_1 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3706.270247408939 - 20 -1115.045252869691 - 10 -3707.47024740894 - 20 -1115.045252869691 - 10 -3707.47024740894 - 20 -1112.839575830113 - 10 -3706.270247408939 - 20 -1112.839575830113 - 0 -LWPOLYLINE - 5 -C50 -100 -AcDbEntity - 8 -BLK_1_LVL_0_SIDE_YARD2 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 9 - 70 - 1 - 43 -0 - 10 -3710.930247410173 - 20 -1115.444751510471 - 10 -3711.089186617583 - 20 -1115.444751510469 - 10 -3711.089094240743 - 20 -1115.453857315655 - 10 -3711.088437912353 - 20 -1115.51855316904 - 10 -3711.085390260873 - 20 -1115.818967437 - 10 -3711.083445397838 - 20 -1116.010677220192 - 10 -3710.968487745084 - 20 -1127.342326958088 - 10 -3710.932387921423 - 20 -1130.90106992539 - 10 -3710.930247410173 - 20 -1130.901118105119 - 0 -LWPOLYLINE - 5 -C51 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3463.112670446746 - 20 -1256.586620183545 - 10 -3463.112670446746 - 20 -1260.786620183557 - 0 -LINE - 5 -C52 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3462.984949602144 - 20 -1256.586620183545 - 11 -3463.112670446746 - 21 -1256.758793690603 - 0 -LWPOLYLINE - 5 -C53 -100 -AcDbEntity - 8 -BLK_1_COVERED_AREA - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 11 - 70 - 1 - 43 -0 - 10 -3699.232776431592 - 20 -1130.901118105156 - 10 -3710.930246801574 - 20 -1130.901118105156 - 10 -3710.930246801574 - 20 -1115.444751510508 - 10 -3707.700246801593 - 20 -1115.444751510508 - 10 -3707.700246801593 - 20 -1115.044751508745 - 10 -3704.785046520098 - 20 -1114.613288594773 - 10 -3704.396763690617 - 20 -1114.555820968006 - 10 -3702.892776431508 - 20 -1114.343383919094 - 10 -3702.892776431508 - 20 -1113.87338391918 - 10 -3699.462776431575 - 20 -1113.873383919063 - 10 -3699.232776431592 - 20 -1113.873383919063 - 0 -MTEXT - 5 -C54 -100 -AcDbEntity - 8 -BLK_1_BSMNT_FRONT_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3856.260514967662 - 20 -1108.027138911895 - 30 -0 - 40 -2.221171874999997 - 41 -22.21171874999997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=10.0 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C55 -100 -AcDbEntity - 8 -BLK_1_BSMNT_REAR_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3856.677019727028 - 20 -1102.45670045686 - 30 -0 - 40 -2.221171874999997 - 41 -22.21171874999997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=10.0 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C56 -100 -AcDbEntity - 8 -BLK_1_BSMNT_SIDE_YARD_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3856.822723814906 - 20 -1096.070570277268 - 30 -0 - 40 -2.221171874999997 - 41 -22.21171874999997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=10.0 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C57 -100 -AcDbEntity - 8 -BLK_1_BSMNT_SIDE_YARD_2 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3856.290121795161 - 20 -1088.50531095391 - 30 -0 - 40 -2.221171874999997 - 41 -22.21171874999997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=10.0 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C58 -100 -AcDbEntity - 8 -BLK_1_LVL_1_FRONT_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3925.790283753418 - 20 -1113.160585340491 - 30 -0 - 40 -2.221171874999997 - 41 -23.93929687499997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=12.90 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C59 -100 -AcDbEntity - 8 -BLK_1_LVL_1_REAR_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3926.206788512785 - 20 -1107.590146885456 - 30 -0 - 40 -2.221171874999997 - 41 -23.93929687499997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=12.90 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C5A -100 -AcDbEntity - 8 -BLK_1_LVL_1_SIDE_YARD1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3926.352492600663 - 20 -1101.204016705864 - 30 -0 - 40 -2.221171874999997 - 41 -23.93929687499997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=12.90 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C5B -100 -AcDbEntity - 8 -BLK_1_LVL_1_SIDE_YARD2 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3925.819890580917 - 20 -1093.638757382506 - 30 -0 - 40 -2.221171874999997 - 41 -23.93929687499997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=12.90 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -C5C -100 -AcDbEntity - 8 -BLK_1_LVL_0_BLDG_FOOT_PRINT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 11 - 70 - 1 - 43 -0 - 10 -3699.232777044987 - 20 -1130.901118125413 - 10 -3710.93024741497 - 20 -1130.901118125413 - 10 -3710.93024741497 - 20 -1115.444751530765 - 10 -3707.700247415093 - 20 -1115.444751530765 - 10 -3707.700247415093 - 20 -1115.044751530742 - 10 -3704.466422998459 - 20 -1115.044751530277 - 10 -3704.466422998459 - 20 -1114.343383939351 - 10 -3702.892777044905 - 20 -1114.343383939351 - 10 -3702.892777044905 - 20 -1113.873383939437 - 10 -3699.462777044971 - 20 -1113.87338393932 - 10 -3699.232777044987 - 20 -1113.87338393932 - 0 -LWPOLYLINE - 5 -C5D -100 -AcDbEntity - 8 -BLK_1_LVL_0_FRONT_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 11 - 70 - 1 - 43 -0 - 10 -3699.232777040066 - 20 -1113.873383919085 - 10 -3702.892776431506 - 20 -1113.873383919075 - 10 -3702.89277643151 - 20 -1114.343383919057 - 10 -3704.46743068438 - 20 -1114.343702468373 - 10 -3704.467387999287 - 20 -1115.045070058 - 10 -3707.700247410171 - 20 -1115.045252870157 - 10 -3707.700247523737 - 20 -1115.444751510496 - 10 -3710.930248785113 - 20 -1115.444751510469 - 10 -3710.931485144911 - 20 -1110.563998297215 - 10 -3710.931545268003 - 20 -1109.58540778369 - 10 -3699.234207207088 - 20 -1107.312053327475 - 0 -LWPOLYLINE - 5 -C5E -100 -AcDbEntity - 8 -BLK_1_LVL_0_SIDE_YARD1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3699.232777040192 - 20 -1130.901118105119 - 10 -3698.034300625808 - 20 -1130.90104516612 - 10 -3698.034302000869 - 20 -1113.8734017972 - 10 -3699.232778415129 - 20 -1113.873414736185 - 0 -LWPOLYLINE - 5 -C5F -100 -AcDbEntity - 8 -BLK_1_BSMNT_REAR_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 1 - 43 -0 - 10 -3699.232777040192 - 20 -1130.901118105156 - 10 -3699.221250807438 - 20 -1132.969197142546 - 10 -3701.361437638996 - 20 -1133.220526157112 - 10 -3710.910075275855 - 20 -1133.07507759163 - 10 -3710.930245187186 - 20 -1130.901118105119 - 0 -LWPOLYLINE - 5 -C60 -100 -AcDbEntity - 8 -BLK_1_LVL_1_REAR_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 1 - 43 -0 - 10 -3699.232777040192 - 20 -1130.901118105156 - 10 -3699.221250807438 - 20 -1132.969197142546 - 10 -3701.361437638996 - 20 -1133.220526157112 - 10 -3710.910075275855 - 20 -1133.07507759163 - 10 -3710.930245187186 - 20 -1130.901118105119 - 10 -3710.920247410536 - 20 -1121.211118103174 - 10 -3701.292777044578 - 20 -1121.211118103815 - 10 -3701.292777044578 - 20 -1130.901118103177 - 0 -LWPOLYLINE - 5 -C61 -100 -AcDbEntity - 8 -BLK_1_LVL_1_FRONT_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 11 - 70 - 1 - 43 -0 - 10 -3699.232777040066 - 20 -1113.873383919085 - 10 -3702.892776431506 - 20 -1113.873383919075 - 10 -3702.89277643151 - 20 -1114.343383919057 - 10 -3704.46743068438 - 20 -1114.343702468373 - 10 -3704.467388003211 - 20 -1117.573292518543 - 10 -3707.700247414094 - 20 -1117.5734753307 - 10 -3707.700247527041 - 20 -1117.573383919618 - 10 -3710.931758942712 - 20 -1117.573384783489 - 10 -3710.931485144911 - 20 -1110.563998297215 - 10 -3710.931545268003 - 20 -1109.58540778369 - 10 -3699.234207207088 - 20 -1107.312053327475 - 0 -LWPOLYLINE - 5 -C62 -100 -AcDbEntity - 8 -BLK_1_LVL_1_SIDE_YARD1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3699.232777040192 - 20 -1130.901118105119 - 10 -3698.034300625808 - 20 -1130.90104516612 - 10 -3698.034302000869 - 20 -1113.8734017972 - 10 -3699.232778415129 - 20 -1113.873414736185 - 0 -LWPOLYLINE - 5 -C63 -100 -AcDbEntity - 8 -BLK_1_LVL_1_SIDE_YARD2 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 12 - 70 - 1 - 43 -0 - 10 -3710.931758837711 - 20 -1117.573417964718 - 10 -3711.067577681534 - 20 -1117.574795823711 - 10 -3711.067343703188 - 20 -1117.597859627006 - 10 -3711.065630789529 - 20 -1117.766705607395 - 10 -3711.062969402351 - 20 -1118.029044882827 - 10 -3711.057994324521 - 20 -1118.519450158549 - 10 -3710.968487745084 - 20 -1127.342326958088 - 10 -3710.93238490432 - 20 -1130.901069993301 - 10 -3710.930247410173 - 20 -1130.901118105119 - 10 -3701.292777044578 - 20 -1130.901118103177 - 10 -3701.292777044578 - 20 -1121.211118103815 - 10 -3710.920247410536 - 20 -1121.211118103174 - 0 -LWPOLYLINE - 5 -C64 -100 -AcDbEntity - 8 -BLK_1_LVL_1_BLDG_FOOT_PRINT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 13 - 70 - 1 - 43 -0 - 10 -3699.232777044987 - 20 -1130.901118084906 - 10 -3701.292777044578 - 20 -1130.901118103177 - 10 -3701.292777044578 - 20 -1121.211118103815 - 10 -3710.920247410536 - 20 -1121.211118103174 - 10 -3710.931758945454 - 20 -1117.573383917096 - 10 -3704.466422995432 - 20 -1117.573383927132 - 10 -3704.466422994034 - 20 -1116.143383917103 - 10 -3704.466422994034 - 20 -1115.044751508506 - 10 -3704.466422994034 - 20 -1114.343383898843 - 10 -3702.892777044905 - 20 -1114.343383898843 - 10 -3702.892777044905 - 20 -1113.873383898928 - 10 -3699.462777044971 - 20 -1113.873383898813 - 10 -3699.232777044987 - 20 -1113.873383898813 - 0 -LWPOLYLINE - 5 -C65 -100 -AcDbEntity - 8 -BLK_1_BSMNT_SIDE_YARD_2 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 9 - 70 - 1 - 43 -0 - 10 -3710.930248795403 - 20 -1115.444710887573 - 10 -3711.090615002316 - 20 -1115.444751510469 - 10 -3711.090522625478 - 20 -1115.453857315655 - 10 -3711.089866297085 - 20 -1115.51855316904 - 10 -3711.086818645604 - 20 -1115.818967437 - 10 -3711.084873782571 - 20 -1116.010677220192 - 10 -3710.969916129818 - 20 -1127.342326958088 - 10 -3710.932384904318 - 20 -1130.901069993495 - 10 -3710.93024741497 - 20 -1130.901118105011 - 0 -DIMENSION - 5 -C66 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_HT_ROOM - 6 -CONTINUOUS - 62 - 4 -370 - -1 -100 -AcDbDimension - 2 -*D88 - 10 -3439.215394900698 - 20 -1248.23662018351 - 30 -0 - 11 -3439.215394900697 - 21 -1247.011620183534 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3439.215394900691 - 23 -1245.78662018356 - 33 -0 - 14 -3439.215394900691 - 24 -1248.23662018351 - 34 -0 - 0 -DIMENSION - 5 -C67 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D89 - 10 -3662.588752883162 - 20 -1134.206780074248 - 30 -0 - 11 -3662.710722531596 - 21 -1147.106833780797 - 31 -0 - 70 - 33 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3663.309089490578 - 23 -1160.007092588285 - 33 -0 - 14 -3663.320197033808 - 24 -1134.20709497922 - 34 -0 - 0 -DIMENSION - 5 -C68 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D90 - 10 -3663.225905775432 - 20 -1160.715069758053 - 30 -0 - 11 -3664.874581399463 - 21 -1161.037181403839 - 31 -0 - 70 - 33 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3666.636202718683 - 23 -1160.3980114637 - 33 -0 - 14 -3663.309089490578 - 24 -1160.007092588285 - 34 -0 - 0 -LWPOLYLINE - 5 -C69 -100 -AcDbEntity - 8 -BLK_1_FLR_0_COVERED_PARKING - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3679.952282838893 - 20 -1149.381636383732 - 10 -3663.397645263938 - 20 -1149.381636383732 - 10 -3663.397645263938 - 20 -1160.007130713757 - 10 -3679.952282838893 - 20 -1160.007130713757 - 0 -ENDSEC - 0 -SECTION - 2 -OBJECTS - 0 -DICTIONARY - 5 -C -330 -0 -100 -AcDbDictionary -281 - 1 - 3 -ACAD_GROUP -350 -D - 0 -DICTIONARY - 5 -D -330 -C -100 -AcDbDictionary -281 - 1 - 0 -ENDSEC - 0 -EOF diff --git a/health-services/facility/CHANGELOG.md b/health-services/facility/CHANGELOG.md index a27826b5875..7d24c53744d 100644 --- a/health-services/facility/CHANGELOG.md +++ b/health-services/facility/CHANGELOG.md @@ -1,5 +1,15 @@ All notable changes to this module will be documented in this file. +## 1.1.2 - 2024-05-29 +- Integrated Core 2.9LTS +- Upgraded to health models 1.0.20 and health common 1.0.16 +- Integrated Boundary v2 functionality +- 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 + ## 1.0.0 -- Base version \ No newline at end of file +- Base version + +## 1.1.0 diff --git a/health-services/facility/pom.xml b/health-services/facility/pom.xml index 0352f386b9b..1eb0038656a 100644 --- a/health-services/facility/pom.xml +++ b/health-services/facility/pom.xml @@ -5,16 +5,17 @@ facility jar facility - 1.0.1 + 1.1.2 - 1.8 + 17 ${java.version} ${java.version} + 1.18.22 org.springframework.boot spring-boot-starter-parent - 2.2.6.RELEASE + 3.2.2 src/main/java @@ -44,36 +45,28 @@ org.egov.common health-services-common - 1.0.8-SNAPSHOT + 1.0.17-SNAPSHOT org.egov.common health-services-models - 1.0.1-SNAPSHOT + 1.0.20-SNAPSHOT compile - org.springframework.boot - spring-boot-starter-data-redis - - - io.lettuce - lettuce-core - - - - - redis.clients - jedis + org.egov.services + tracer + 2.9.0-SNAPSHOT org.flywaydb flyway-core + 9.22.3 org.postgresql postgresql - 42.2.2.jre7 + 42.7.1 org.springframework.boot @@ -90,17 +83,24 @@ org.projectlombok lombok + ${lombok.version} true - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 + junit + junit + 4.13.2 + test + + + jakarta.validation + jakarta.validation-api + 3.0.2 + compile - - javax.validation - validation-api + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 diff --git a/health-services/facility/src/main/java/org/egov/facility/config/FacilityConfiguration.java b/health-services/facility/src/main/java/org/egov/facility/config/FacilityConfiguration.java index 503f83b2f32..d92cf5b04b7 100644 --- a/health-services/facility/src/main/java/org/egov/facility/config/FacilityConfiguration.java +++ b/health-services/facility/src/main/java/org/egov/facility/config/FacilityConfiguration.java @@ -35,4 +35,10 @@ public class FacilityConfiguration { @Value("${facility.idgen.id.format}") private String facilityIdFormat; + + @Value("${egov.boundary.host}") + private String boundaryServiceHost; + + @Value("${egov.boundary.search.url}") + private String boundarySearchUrl; } diff --git a/health-services/facility/src/main/java/org/egov/facility/config/MainConfiguration.java b/health-services/facility/src/main/java/org/egov/facility/config/MainConfiguration.java index 34cf8965b63..0c88de6e214 100644 --- a/health-services/facility/src/main/java/org/egov/facility/config/MainConfiguration.java +++ b/health-services/facility/src/main/java/org/egov/facility/config/MainConfiguration.java @@ -22,7 +22,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.util.TimeZone; @Import({TracerConfiguration.class}) @Configuration diff --git a/health-services/facility/src/main/java/org/egov/facility/consumer/FacilityConsumer.java b/health-services/facility/src/main/java/org/egov/facility/consumer/FacilityConsumer.java index e05edce134c..424dc8eb71f 100644 --- a/health-services/facility/src/main/java/org/egov/facility/consumer/FacilityConsumer.java +++ b/health-services/facility/src/main/java/org/egov/facility/consumer/FacilityConsumer.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilityBulkRequest; import org.egov.facility.service.FacilityService; @@ -33,7 +34,7 @@ public List bulkCreate(Map consumerRecord, FacilityBulkRequest request = objectMapper.convertValue(consumerRecord, FacilityBulkRequest.class); return service.create(request, true); } catch (Exception exception) { - log.error("error in facility consumer bulk create", exception); + log.error("error in facility consumer bulk create: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -45,7 +46,7 @@ public List bulkUpdate(Map consumerRecord, FacilityBulkRequest request = objectMapper.convertValue(consumerRecord, FacilityBulkRequest.class); return service.update(request, true); } catch (Exception exception) { - log.error("error in facility consumer bulk update", exception); + log.error("error in facility consumer bulk update: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -57,7 +58,7 @@ public List bulkDelete(Map consumerRecord, FacilityBulkRequest request = objectMapper.convertValue(consumerRecord, FacilityBulkRequest.class); return service.delete(request, true); } catch (Exception exception) { - log.error("error in facility consumer bulk delete", exception); + log.error("error in facility consumer bulk delete: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java b/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java index 9555237132a..482ac988b98 100644 --- a/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java +++ b/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java @@ -13,6 +13,7 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; import java.lang.reflect.Method; @@ -35,9 +36,12 @@ public FacilityRepository(Producer producer, NamedParameterJdbcTemplate namedPar } public List findById(List ids, String columnName, Boolean includeDeleted) { - List objFound = findInCache(ids).stream() - .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) - .collect(Collectors.toList()); + List objFound = findInCache(ids); + if (!includeDeleted) { + objFound = objFound.stream() + .filter(entity -> entity.getIsDeleted().equals(false)) + .collect(Collectors.toList()); + } if (!objFound.isEmpty()) { Method idMethod = getIdMethod(objFound, columnName); ids.removeAll(objFound.stream() @@ -48,9 +52,9 @@ public List findById(List ids, String columnName, Boolean incl } } - String query = String.format("SELECT * FROM facility f LEFT JOIN address a ON f.addressid = a.id WHERE f.%s IN (:ids) AND isDeleted = false", columnName); + String query = String.format("SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM facility f LEFT JOIN address a ON f.addressid = a.id WHERE f.%s IN (:ids) AND isDeleted = false", columnName); if (null != includeDeleted && includeDeleted) { - query = String.format("SELECT * FROM facility f LEFT JOIN address a ON f.addressid = a.id WHERE f.%s IN (:ids)", columnName); + query = String.format("SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM facility f LEFT JOIN address a ON f.addressid = a.id WHERE f.%s IN (:ids)", columnName); } Map paramMap = new HashMap(); paramMap.put("ids", ids); @@ -61,13 +65,17 @@ public List findById(List ids, String columnName, Boolean incl } public List find(FacilitySearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { - String query = "SELECT * FROM facility f LEFT JOIN address a ON f.addressid = a.id"; + String query = "SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM facility f LEFT JOIN address a ON f.addressid = a.id"; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); query = query.replace("id IN (:id)", "f.id IN (:id)"); - query = query + " and f.tenantId=:tenantId "; + if(CollectionUtils.isEmpty(whereFields)) { + query = query + " where f.tenantId=:tenantId "; + } else { + query = query + " and f.tenantId=:tenantId "; + } if (Boolean.FALSE.equals(includeDeleted)) { query = query + "and isDeleted=:isDeleted "; } diff --git a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java index 8258ab1476f..3517293adcf 100644 --- a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java +++ b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java @@ -1,19 +1,19 @@ package org.egov.facility.repository.rowmapper; +import java.sql.ResultSet; +import java.sql.SQLException; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.facility.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.facility.Address; import org.egov.common.models.facility.AddressType; -import org.egov.common.models.facility.Boundary; +import org.egov.common.models.core.Boundary; import org.egov.common.models.facility.Facility; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import java.sql.ResultSet; -import java.sql.SQLException; - @Component public class FacilityRowMapper implements RowMapper { @@ -22,7 +22,7 @@ public class FacilityRowMapper implements RowMapper { @Override public Facility mapRow(ResultSet resultSet, int i) throws SQLException { try { - return Facility.builder() + Facility facility = Facility.builder() .id(resultSet.getString("id")) .clientReferenceId(resultSet.getString("clientReferenceId")) .tenantId(resultSet.getString("tenantId")) @@ -31,8 +31,8 @@ public Facility mapRow(ResultSet resultSet, int i) throws SQLException { .usage(resultSet.getString("usage")) .storageCapacity(resultSet.getInt("storageCapacity")) .address(Address.builder() - .id(resultSet.getString(15)) - .tenantId(resultSet.getString(16)) + .id(resultSet.getString("aid")) + .tenantId(resultSet.getString("atenantid")) .doorNo(resultSet.getString("doorNo")) .latitude(resultSet.getDouble("latitude")) .longitude(resultSet.getDouble("longitude")) @@ -45,7 +45,7 @@ public Facility mapRow(ResultSet resultSet, int i) throws SQLException { .pincode(resultSet.getString("pinCode")) .buildingName(resultSet.getString("buildingName")) .street(resultSet.getString("street")) - .locality(Boundary.builder().code(resultSet.getString("localityCode")).build()) + .locality(resultSet.getString("localityCode") != null ? Boundary.builder().code(resultSet.getString("localityCode")).build() : null) .build()) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) @@ -58,6 +58,10 @@ public Facility mapRow(ResultSet resultSet, int i) throws SQLException { .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) .build(); + if (facility.getAddress().getId() == null) { + facility.setAddress(null); + } + return facility; } catch (JsonProcessingException e) { throw new SQLException(e); } diff --git a/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java b/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java index 9f40852ecdf..769aae4b725 100644 --- a/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java +++ b/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java @@ -1,6 +1,7 @@ package org.egov.facility.service; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.facility.Facility; @@ -11,6 +12,7 @@ import org.egov.facility.config.FacilityConfiguration; import org.egov.facility.repository.FacilityRepository; import org.egov.facility.service.enrichment.FacilityEnrichmentService; +import org.egov.facility.validator.FBoundaryValidator; import org.egov.facility.validator.FIsDeletedValidator; import org.egov.facility.validator.FNonExistentValidator; import org.egov.facility.validator.FNullIdValidator; @@ -52,12 +54,16 @@ public class FacilityService { private final FacilityEnrichmentService enrichmentService; + private final Predicate> isApplicableForCreate = + validator -> validator.getClass().equals(FBoundaryValidator.class); + private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(FIsDeletedValidator.class) - || validator.getClass().equals(FNonExistentValidator.class) - || validator.getClass().equals(FNullIdValidator.class) - || validator.getClass().equals(FRowVersionValidator.class) - || validator.getClass().equals(FUniqueEntityValidator.class); + || validator.getClass().equals(FBoundaryValidator.class) + || validator.getClass().equals(FNonExistentValidator.class) + || validator.getClass().equals(FNullIdValidator.class) + || validator.getClass().equals(FRowVersionValidator.class) + || validator.getClass().equals(FUniqueEntityValidator.class); private final Predicate> isApplicableForDelete = validator -> validator.getClass().equals(FNonExistentValidator.class) @@ -83,9 +89,12 @@ public Facility create(FacilityRequest request) { public List create(FacilityBulkRequest request, boolean isBulk) { log.info("starting create method for facility"); - Map errorDetailsMap = new HashMap<>(); - List validEntities = request.getFacilities(); + Tuple, Map> tuple = validate(validators, + isApplicableForCreate, request, SET_FACILITIES, GET_FACILITIES, VALIDATION_ERROR, + isBulk); + Map errorDetailsMap = tuple.getY(); + List validEntities = tuple.getX(); try { if (!validEntities.isEmpty()) { log.info("processing {} valid entities", validEntities.size()); @@ -93,7 +102,7 @@ public List create(FacilityBulkRequest request, boolean isBulk) { facilityRepository.save(validEntities, configuration.getCreateFacilityTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_FACILITIES); } @@ -124,7 +133,7 @@ public List update(FacilityBulkRequest request, boolean isBulk) { facilityRepository.save(validEntities, configuration.getUpdateFacilityTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_FACILITIES); } @@ -155,7 +164,7 @@ public List delete(FacilityBulkRequest request, boolean isBulk) { facilityRepository.save(validEntities, configuration.getDeleteFacilityTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_FACILITIES); } diff --git a/health-services/facility/src/main/java/org/egov/facility/validator/FBoundaryValidator.java b/health-services/facility/src/main/java/org/egov/facility/validator/FBoundaryValidator.java new file mode 100644 index 00000000000..2919150eb65 --- /dev/null +++ b/health-services/facility/src/main/java/org/egov/facility/validator/FBoundaryValidator.java @@ -0,0 +1,127 @@ +package org.egov.facility.validator; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.core.Boundary; +import org.egov.common.models.facility.Facility; +import org.egov.common.models.facility.FacilityBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.facility.config.FacilityConfiguration; +import org.egov.facility.web.models.boundary.BoundaryResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +/** + * Validator class for validating facility boundaries. + */ +@Component +@Order(value = 4) +@Slf4j +public class FBoundaryValidator implements Validator { + + private final ServiceRequestClient serviceRequestClient; + + private final FacilityConfiguration facilityConfiguration; + + /** + * Constructor to initialize the HBoundaryValidator. + * + * @param serviceRequestClient Service request client for making HTTP requests + * @param facilityConfiguration Configuration properties for the facility module + */ + public FBoundaryValidator(ServiceRequestClient serviceRequestClient, FacilityConfiguration facilityConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.facilityConfiguration = facilityConfiguration; + } + + /** + * Validates the facilities' boundaries. + * + * @param request the bulk request containing facilities + * @return a map containing facilities with their corresponding list of errors + */ + @Override + public Map> validate(FacilityBulkRequest request) { + log.debug("Validating facilities boundaries."); + // Create a HashMap to store error details for each facility + HashMap> errorDetailsMap = new HashMap<>(); + + // Filter facilities with non-null addresses + List entitiesWithValidBoundaries = request.getFacilities().parallelStream() + .filter(facility -> Objects.nonNull(facility.getAddress())) + .filter(facility -> Objects.nonNull(facility.getAddress().getLocality())) // Exclude null locality codes + .collect(Collectors.toList()); + + Map> tenantIdFacilityMap = entitiesWithValidBoundaries.stream().collect(Collectors.groupingBy(Facility::getTenantId)); + + tenantIdFacilityMap.forEach((tenantId, facilities) -> { + // Group facilities by locality code + Map> boundaryCodeFacilitysMap = facilities.stream() + .collect(Collectors.groupingBy( + facility -> facility.getAddress().getLocality().getCode() // Group by locality code + )); + + List boundaries = new ArrayList<>(boundaryCodeFacilitysMap.keySet()); + if(!CollectionUtils.isEmpty(boundaries)) { + try { + // Fetch boundary details from the service + log.debug("Fetching boundary details for tenantId: {}, boundaries: {}", tenantId, boundaries); + BoundaryResponse boundarySearchResponse = serviceRequestClient.fetchResult( + new StringBuilder(facilityConfiguration.getBoundaryServiceHost() + + facilityConfiguration.getBoundarySearchUrl() + +"?limit=" + boundaries.size() + + "&offset=0&tenantId=" + tenantId + + "&codes=" + String.join(",", boundaries)), + request.getRequestInfo(), + BoundaryResponse.class + ); + log.debug("Boundary details fetched successfully for tenantId: {}", tenantId); + + List invalidBoundaryCodes = new ArrayList<>(boundaries); + invalidBoundaryCodes.removeAll(boundarySearchResponse.getBoundary().stream() + .map(Boundary::getCode) + .collect(Collectors.toList()) + ); + + // Filter out facilities with invalid boundary codes + List facilitiesWithInvalidBoundaries = boundaryCodeFacilitysMap.entrySet().stream() + .filter(entry -> invalidBoundaryCodes.contains(entry.getKey())) // filter invalid boundary codes + .flatMap(entry -> entry.getValue().stream()) // Flatten the list of facilities + .collect(Collectors.toList()); + + + facilitiesWithInvalidBoundaries.forEach(facility -> { + // Create an error object for facilities with invalid boundaries + Error error = Error.builder() + .errorMessage("Boundary code does not exist in db") + .errorCode("NON_EXISTENT_ENTITY") + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException("NON_EXISTENT_ENTITY", "Boundary code does not exist in db")) + .build(); + // Populate error details for the facility + populateErrorDetails(facility, error, errorDetailsMap); + }); + + } catch (Exception e) { + log.error("Exception while searching boundaries for tenantId: {}", tenantId, e); + // Throw a custom exception if an error occurs during boundary search + throw new CustomException("BOUNDARY_SERVICE_SEARCH_ERROR","Error in while fetching boundaries from Boundary Service : " + e.getMessage()); + } + } + }); + + return errorDetailsMap; + } +} diff --git a/health-services/facility/src/main/java/org/egov/facility/web/controllers/FacilityApiController.java b/health-services/facility/src/main/java/org/egov/facility/web/controllers/FacilityApiController.java index c7db346d9a6..3ca37071ca8 100644 --- a/health-services/facility/src/main/java/org/egov/facility/web/controllers/FacilityApiController.java +++ b/health-services/facility/src/main/java/org/egov/facility/web/controllers/FacilityApiController.java @@ -1,9 +1,14 @@ package org.egov.facility.web.controllers; +import java.util.List; + import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.URLParams; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilityBulkRequest; import org.egov.common.models.facility.FacilityBulkResponse; @@ -18,19 +23,10 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; - -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.util.List; - -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") @Controller @RequestMapping("") @@ -111,11 +107,17 @@ public ResponseEntity facilityV1DeletePost(@ApiParam(value = " } @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) - public ResponseEntity facilityV1SearchPost(@ApiParam(value = "Details for existing facility.", required = true) @Valid @RequestBody FacilitySearchRequest request, @NotNull - @Min(0) - @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull - @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { - List facilities = facilityService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); + public ResponseEntity facilityV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Details for existing facility.", required = true) @Valid @RequestBody FacilitySearchRequest request + ) throws Exception { + List facilities = facilityService.search( + request, + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted()); FacilityBulkResponse response = FacilityBulkResponse.builder().responseInfo(ResponseInfoFactory .createResponseInfo(request.getRequestInfo(), true)).facilities(facilities).build(); diff --git a/health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundaryRequest.java b/health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundaryRequest.java new file mode 100644 index 00000000000..78efab9d986 --- /dev/null +++ b/health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundaryRequest.java @@ -0,0 +1,38 @@ +package org.egov.facility.web.models.boundary; + +import java.util.List; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryRequest + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @Valid + @NotNull + @JsonProperty("Boundary") + @Size(min = 1, max = 300) + private List boundary = null; + +} diff --git a/health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundaryResponse.java b/health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundaryResponse.java new file mode 100644 index 00000000000..a05cd2437cd --- /dev/null +++ b/health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundaryResponse.java @@ -0,0 +1,44 @@ +package org.egov.facility.web.models.boundary; + +import java.util.ArrayList; +import java.util.List; +import jakarta.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryResponse + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Boundary") + @Valid + private List boundary = null; + + + public BoundaryResponse addBoundaryItem(Boundary boundaryItem) { + if (this.boundary == null) { + this.boundary = new ArrayList<>(); + } + this.boundary.add(boundaryItem); + return this; + } + +} diff --git a/health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundarySearchCriteria.java b/health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundarySearchCriteria.java new file mode 100644 index 00000000000..6f2780fa4c9 --- /dev/null +++ b/health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundarySearchCriteria.java @@ -0,0 +1,37 @@ +package org.egov.facility.web.models.boundary; + +import java.util.List; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundarySearchCriteria { + + @NotNull + @Size(min = 1) + @JsonProperty("codes") + private List codes; + + @NotNull + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} diff --git a/health-services/facility/src/main/resources/application.properties b/health-services/facility/src/main/resources/application.properties index 6e8b6a05ae0..f25c5a93406 100644 --- a/health-services/facility/src/main/resources/application.properties +++ b/health-services/facility/src/main/resources/application.properties @@ -80,3 +80,9 @@ facility.consumer.bulk.update.topic=update-facility-bulk-topic facility.kafka.create.topic=save-facility-topic facility.kafka.update.topic=update-facility-topic facility.kafka.delete.topic=delete-facility-topic + + +# BOUNDARY SERVICE +egov.boundary.host=http://localhost:8081 +egov.boundary.search.url=/boundary-service/boundary/_search +egov.boundary.hierarchy=HCM-Moz-Hierarchy diff --git a/health-services/facility/src/main/resources/db/Dockerfile b/health-services/facility/src/main/resources/db/Dockerfile index 60fc07ce69f..e7da01d7f0b 100644 --- a/health-services/facility/src/main/resources/db/Dockerfile +++ b/health-services/facility/src/main/resources/db/Dockerfile @@ -1,4 +1,4 @@ -FROM egovio/flyway:4.1.2 +FROM egovio/flyway:10.7.1 COPY ./migration/main /flyway/sql @@ -6,4 +6,4 @@ COPY migrate.sh /usr/bin/migrate.sh RUN chmod +x /usr/bin/migrate.sh -CMD ["/usr/bin/migrate.sh"] \ No newline at end of file +ENTRYPOINT ["/usr/bin/migrate.sh"] \ No newline at end of file diff --git a/health-services/facility/src/main/resources/db/migrate.sh b/health-services/facility/src/main/resources/db/migrate.sh index 43960b25cdb..f9d6617822c 100644 --- a/health-services/facility/src/main/resources/db/migrate.sh +++ b/health-services/facility/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/facility/src/test/java/org/egov/facility/helper/FacilityTestBuilder.java b/health-services/facility/src/test/java/org/egov/facility/helper/FacilityTestBuilder.java index 8b4b27934fe..3a9eb405169 100644 --- a/health-services/facility/src/test/java/org/egov/facility/helper/FacilityTestBuilder.java +++ b/health-services/facility/src/test/java/org/egov/facility/helper/FacilityTestBuilder.java @@ -7,10 +7,10 @@ public class FacilityTestBuilder { - private final Facility.FacilityBuilder builder; + private final Facility.FacilityBuilder builder; public FacilityTestBuilder() { - this.builder = Facility.builder(); + this.builder = (Facility.FacilityBuilder) Facility.builder(); } public static FacilityTestBuilder builder() { diff --git a/health-services/household/CHANGELOG.md b/health-services/household/CHANGELOG.md index a27826b5875..3b9cbec0526 100644 --- a/health-services/household/CHANGELOG.md +++ b/health-services/household/CHANGELOG.md @@ -1,5 +1,37 @@ All notable changes to this module will be documented in this file. +## 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 +- MDMS v2 integration +- 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 + +## 1.1.2 - 2024-05-10 + +- Integrated Boundary v2 functionality + +## 1.1.1 - 2023-11-15 + +- Added total count for household +- Added a field for HouseholdMember-clientReferenceId + +## 1.1.1-beta + +- Added proximity based search support + +## 1.1.0 + + ## 1.0.0 -- Base version \ No newline at end of file +- Base version + diff --git a/health-services/household/README.md b/health-services/household/README.md index a448bda922e..6041a0ccde0 100644 --- a/health-services/household/README.md +++ b/health-services/household/README.md @@ -79,3 +79,11 @@ Household service APIs - contains create, update, delete and search end point ## Pre commit script [commit-msg](https://gist.github.com/jayantp-egov/14f55deb344f1648503c6be7e580fa12) + +## Updates +- Household Member Search + - `householdId`, `householdClientReferenceId`, `individualId`, and `individualClientReferenceId` now accepts a list of entities instead of single entity to search household member +## Usage +- Start the service +- Access the API endpoints for searching `household member` +- Pass list parameters for the search fields mentioned in updates \ No newline at end of file diff --git a/health-services/household/pom.xml b/health-services/household/pom.xml index 9d6d7361f09..798eba22c92 100644 --- a/health-services/household/pom.xml +++ b/health-services/household/pom.xml @@ -5,16 +5,17 @@ household jar household - 1.0.0 + 1.1.4 - 1.8 + 17 ${java.version} ${java.version} + 1.18.22 org.springframework.boot spring-boot-starter-parent - 2.2.6.RELEASE + 3.2.2 src/main/java @@ -44,28 +45,40 @@ org.egov.common health-services-common - 1.0.8-SNAPSHOT + 1.0.18-SNAPSHOT org.egov.common health-services-models - 1.0.0-SNAPSHOT + 1.0.20-SNAPSHOT compile org.flywaydb flyway-core + 9.22.3 org.postgresql postgresql - 42.2.2.jre7 + 42.7.1 + + + org.egov.services + tracer + 2.9.0-SNAPSHOT org.springframework.boot spring-boot-starter-test test + + junit + junit + 4.13.2 + test + io.swagger swagger-core @@ -75,6 +88,7 @@ org.projectlombok lombok + ${lombok.version} true @@ -82,11 +96,6 @@ com.fasterxml.jackson.datatype jackson-datatype-jsr310 - - - javax.validation - validation-api - diff --git a/health-services/household/src/main/java/org/egov/household/Constants.java b/health-services/household/src/main/java/org/egov/household/Constants.java index c32122f155f..0ce22b8bb8d 100644 --- a/health-services/household/src/main/java/org/egov/household/Constants.java +++ b/health-services/household/src/main/java/org/egov/household/Constants.java @@ -5,6 +5,8 @@ public interface Constants { String GET_ID = "getId"; + String GET_CLIENT_REFERENCE_ID = "getClientReferenceId"; + String GET_INDIVIDUAL_ID = "getIndividualId"; String GET_INDIVIDUAL_CLIENT_REFERENCE_ID = "getIndividualClientReferenceId"; @@ -21,7 +23,7 @@ public interface Constants { String INDIVIDUAL_ALREADY_MEMBER_OF_HOUSEHOLD = "INDIVIDUAL_ALREADY_MEMBER_OF_HOUSEHOLD"; - String INDIVIDUAL_ALREADY_MEMBER_OF_HOUSEHOLD_MESSAGE = "individual is already member od household"; + String INDIVIDUAL_ALREADY_MEMBER_OF_HOUSEHOLD_MESSAGE = "individual is already member of household"; String INDIVIDUAL_NOT_FOUND = "INDIVIDUAL_NOT_FOUND"; diff --git a/health-services/household/src/main/java/org/egov/household/config/HouseholdConfiguration.java b/health-services/household/src/main/java/org/egov/household/config/HouseholdConfiguration.java index 889b1393141..c906d52786f 100644 --- a/health-services/household/src/main/java/org/egov/household/config/HouseholdConfiguration.java +++ b/health-services/household/src/main/java/org/egov/household/config/HouseholdConfiguration.java @@ -37,4 +37,9 @@ public class HouseholdConfiguration { @Value("${household.idgen.id.format}") private String idgenFormat; + @Value("${egov.boundary.host}") + private String boundaryServiceHost; + + @Value("${egov.boundary.search.url}") + private String boundarySearchUrl; } diff --git a/health-services/household/src/main/java/org/egov/household/config/MainConfiguration.java b/health-services/household/src/main/java/org/egov/household/config/MainConfiguration.java index c04b49176dd..edfc34ac8d6 100644 --- a/health-services/household/src/main/java/org/egov/household/config/MainConfiguration.java +++ b/health-services/household/src/main/java/org/egov/household/config/MainConfiguration.java @@ -22,7 +22,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.util.TimeZone; @Import({TracerConfiguration.class}) @Configuration diff --git a/health-services/household/src/main/java/org/egov/household/consumer/HouseholdConsumer.java b/health-services/household/src/main/java/org/egov/household/consumer/HouseholdConsumer.java index 7bc27e9bbd2..dcaf3d491ab 100644 --- a/health-services/household/src/main/java/org/egov/household/consumer/HouseholdConsumer.java +++ b/health-services/household/src/main/java/org/egov/household/consumer/HouseholdConsumer.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdBulkRequest; import org.egov.household.service.HouseholdService; @@ -38,7 +39,7 @@ public List bulkCreate(Map consumerRecord, HouseholdBulkRequest request = objectMapper.convertValue(consumerRecord, HouseholdBulkRequest.class); return householdService.create(request, true); } catch (Exception exception) { - log.error("error in household consumer bulk create", exception); + log.error("error in household consumer bulk create: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -50,7 +51,7 @@ public List bulkUpdate(Map consumerRecord, HouseholdBulkRequest request = objectMapper.convertValue(consumerRecord, HouseholdBulkRequest.class); return householdService.update(request, true); } catch (Exception exception) { - log.error("error in household consumer bulk update", exception); + log.error("error in household consumer bulk update: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -62,7 +63,7 @@ public List bulkDelete(Map consumerRecord, HouseholdBulkRequest request = objectMapper.convertValue(consumerRecord, HouseholdBulkRequest.class); return householdService.delete(request, true); } catch (Exception exception) { - log.error("error in household consumer bulk delete", exception); + log.error("error in household consumer bulk delete: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/household/src/main/java/org/egov/household/consumer/HouseholdMemberConsumer.java b/health-services/household/src/main/java/org/egov/household/consumer/HouseholdMemberConsumer.java index 11bc1709232..35acb74b53f 100644 --- a/health-services/household/src/main/java/org/egov/household/consumer/HouseholdMemberConsumer.java +++ b/health-services/household/src/main/java/org/egov/household/consumer/HouseholdMemberConsumer.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.household.HouseholdMember; import org.egov.common.models.household.HouseholdMemberBulkRequest; import org.egov.household.service.HouseholdMemberService; @@ -38,7 +39,7 @@ public List bulkCreate(Map consumerRecord, HouseholdMemberBulkRequest request = objectMapper.convertValue(consumerRecord, HouseholdMemberBulkRequest.class); return householdMemberService.create(request, true); } catch (Exception exception) { - log.error("error in household member consumer bulk create", exception); + log.error("error in household member consumer bulk create: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -50,7 +51,7 @@ public List bulkUpdate(Map consumerRecord, HouseholdMemberBulkRequest request = objectMapper.convertValue(consumerRecord, HouseholdMemberBulkRequest.class); return householdMemberService.update(request, true); } catch (Exception exception) { - log.error("error in household member consumer bulk update", exception); + log.error("error in household member consumer bulk update: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -62,7 +63,7 @@ public List bulkDelete(Map consumerRecord, HouseholdMemberBulkRequest request = objectMapper.convertValue(consumerRecord, HouseholdMemberBulkRequest.class); return householdMemberService.delete(request, true); } catch (Exception exception) { - log.error("error in household member consumer bulk delete", exception); + log.error("error in household member consumer bulk delete: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmExistentEntityValidator.java b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmExistentEntityValidator.java new file mode 100644 index 00000000000..cc9eb6c12d7 --- /dev/null +++ b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmExistentEntityValidator.java @@ -0,0 +1,96 @@ +package org.egov.household.household.member.validators; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.household.HouseholdMember; +import org.egov.common.models.household.HouseholdMemberBulkRequest; +import org.egov.common.models.household.HouseholdMemberSearch; +import org.egov.common.validator.Validator; +import org.egov.household.repository.HouseholdMemberRepository; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of entities with the given client reference IDs. + * This validator checks if the provided HouseholdMember entities already exist in the database based on their client reference IDs. + * + * @author kanishq-egov + */ +@Component +@Order(value = 1) +@Slf4j +public class HmExistentEntityValidator implements Validator { + + private final HouseholdMemberRepository householdMemberRepository; + + /** + * Constructor to initialize the HouseholdMemberRepository dependency. + * + * @param householdMemberRepository The repository for HouseholdMember entities. + */ + public HmExistentEntityValidator(HouseholdMemberRepository householdMemberRepository) { + this.householdMemberRepository = householdMemberRepository; + } + + /** + * Validates the existence of entities with the given client reference IDs. + * This method checks if any of the HouseholdMember entities in the request already exist in the database, + * based on their client reference IDs. If an entity is found to exist, an error is added to the error details map. + * + * @param request The bulk request containing HouseholdMember entities. + * @return A map containing HouseholdMember entities and their associated error details, if any. + */ + @Override + public Map> validate(HouseholdMemberBulkRequest request) { + // Map to hold HouseholdMember entities and their associated error details + Map> errorDetailsMap = new HashMap<>(); + + // Get the list of HouseholdMember entities from the request + List entities = request.getHouseholdMembers(); + + // Extract client reference IDs from HouseholdMember entities that do not have errors + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) // Filter out entities that already have errors + .map(HouseholdMember::getClientReferenceId) // Map to client reference IDs + .collect(Collectors.toList()); // Collect the IDs into a list + + // Create a search object for querying entities by client reference IDs + HouseholdMemberSearch householdSearch = HouseholdMemberSearch.builder() + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search + .build(); + + // Create a map of client reference ID to HouseholdMember entity for easy lookup + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + + // Check if the client reference ID list is not empty before querying the database + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing entities by client reference IDs + List existingClientReferenceIds = + householdMemberRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, populate error details for uniqueness + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation + Error error = getErrorForUniqueEntity(); + // Populate error details for the HouseholdMember entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); + }); + } + + // Return the map containing HouseholdMember entities and their associated error details + return errorDetailsMap; + } +} diff --git a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdHeadValidator.java b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdHeadValidator.java index 6196b6328f4..09999669c9e 100644 --- a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdHeadValidator.java +++ b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdHeadValidator.java @@ -70,7 +70,7 @@ private void validateHeadOfHousehold(HouseholdMember householdMember, Method idM log.info("validating if household already has a head"); List householdMembersHeadCheck = householdMemberRepository .findIndividualByHousehold((String) ReflectionUtils.invokeMethod(idMethod, householdMember), - columnName).stream().filter(HouseholdMember::getIsHeadOfHousehold) + columnName).getResponse().stream().filter(HouseholdMember::getIsHeadOfHousehold) .collect(Collectors.toList()); if(!householdMembersHeadCheck.isEmpty()){ diff --git a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdValidator.java b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdValidator.java index 7294e0a8296..6c97049b779 100644 --- a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdValidator.java +++ b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdValidator.java @@ -53,7 +53,7 @@ public Map> validate(HouseholdMemberBulkRequest hou List houseHoldIds = getIdList(householdMembers, idMethod); log.info("finding valid household ids from household service"); - List validHouseHoldIds = householdService.findById(houseHoldIds, columnName, false); + List validHouseHoldIds = householdService.findById(houseHoldIds, columnName, false).getResponse(); log.info("getting unique household ids from valid household ids"); Set uniqueHoldIds = getSet(validHouseHoldIds, columnName == "id" ? "getId": "getClientReferenceId"); diff --git a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmNonExistentEntityValidator.java b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmNonExistentEntityValidator.java index ee740ccab6e..6440a640f3a 100644 --- a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmNonExistentEntityValidator.java +++ b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmNonExistentEntityValidator.java @@ -1,24 +1,25 @@ package org.egov.household.household.member.validators; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; import org.egov.common.models.household.HouseholdMember; import org.egov.common.models.household.HouseholdMemberBulkRequest; +import org.egov.common.models.household.HouseholdMemberSearch; import org.egov.common.validator.Validator; import org.egov.household.repository.HouseholdMemberRepository; +import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdToObjMap; import static org.egov.common.utils.CommonUtils.getMethod; import static org.egov.common.utils.CommonUtils.getObjClass; @@ -27,6 +28,11 @@ import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; import static org.egov.household.Constants.GET_ID; +/** + * Validator class for checking the non-existence of household members. + * This validator checks if the provided household members do not already exist in the database. + * @author kanishq-egov + */ @Component @Order(value = 4) @Slf4j @@ -34,33 +40,78 @@ public class HmNonExistentEntityValidator implements Validator> validate(HouseholdMemberBulkRequest request) { + // Map to hold household members and their error details Map> errorDetailsMap = new HashMap<>(); + // Get the list of household members from the request List householdMembers = request.getHouseholdMembers(); - log.info("validating non existent household member"); + // Log message for validation process + log.info("Validating non-existent household members"); + // Get class and method information for ID retrieval Class objClass = getObjClass(householdMembers); Method idMethod = getMethod(GET_ID, objClass); + // Create a map of household members with their IDs as keys Map iMap = getIdToObjMap(householdMembers .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + + // Lists to store IDs and client reference IDs + List idList = new ArrayList<>(); + List clientReferenceIdList = new ArrayList<>(); + // Extract IDs and client reference IDs from household entities + householdMembers.forEach(householdMember -> { + idList.add(householdMember.getId()); + clientReferenceIdList.add(householdMember.getClientReferenceId()); + }); + + // Check if the map is not empty if (!iMap.isEmpty()) { - List householdMemberIds = new ArrayList<>(iMap.keySet()); - List existingHouseholdMembers = householdMemberRepository.findById(householdMemberIds, - getIdFieldName(idMethod), false); + + // Create a search object for querying existing entities + HouseholdMemberSearch householdMemberSearch = HouseholdMemberSearch.builder() + .clientReferenceId(clientReferenceIdList) + .id(idList) + .build(); + + List existingHouseholdMembers; + try { + // Query the repository to find existing entities + existingHouseholdMembers = householdMemberRepository.find(householdMemberSearch, householdMembers.size(), 0, + householdMembers.get(0).getTenantId(), null, false).getResponse(); + } catch (Exception e) { + // Handle query builder exception + log.error("Search failed for HouseholdMember with error: {}", e.getMessage(), e); + throw new CustomException("HOUSEHOLD_MEMBER_SEARCH_FAILED", "Search Failed for HouseholdMember, " + e.getMessage()); + } + + // Check for non-existent household members List nonExistentIndividuals = checkNonExistentEntities(iMap, existingHouseholdMembers, idMethod); + // For each non-existent household member, populate error details nonExistentIndividuals.forEach(householdMember -> { Error error = getErrorForNonExistentEntity(); populateErrorDetails(householdMember, error, errorDetailsMap); }); } - log.info("household member non existent validation completed successfully, total errors: " + errorDetailsMap.size()); + // Log message for validation completion + log.info("Household member non-existent validation completed successfully, total errors: " + errorDetailsMap.size()); return errorDetailsMap; } } diff --git a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmRowVersionValidator.java b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmRowVersionValidator.java index fb9ec3cdd98..18d77c76920 100644 --- a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmRowVersionValidator.java +++ b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmRowVersionValidator.java @@ -50,7 +50,7 @@ public Map> validate(HouseholdMemberBulkRequest req if (!iMap.isEmpty()) { List householdMemberIds = new ArrayList<>(iMap.keySet()); List existingHouseholdMembers = householdMemberRepository.findById(householdMemberIds, - getIdFieldName(idMethod), false); + getIdFieldName(idMethod), false).getResponse(); List entitiesWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(iMap, existingHouseholdMembers, idMethod); entitiesWithMismatchedRowVersion.forEach(householdMember -> { diff --git a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmUniqueIndividualValidator.java b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmUniqueIndividualValidator.java index 0d2f4682dce..535c842f81f 100644 --- a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmUniqueIndividualValidator.java +++ b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmUniqueIndividualValidator.java @@ -69,7 +69,7 @@ public Map> validate(HouseholdMemberBulkRequest hou log.info("finding individuals mappings in household member"); List individualSearchResult = householdMemberRepository - .findIndividual(individual.getId()); + .findIndividual(individual.getId()).getResponse(); if(!individualSearchResult.isEmpty()) { Error error = Error.builder().errorMessage(INDIVIDUAL_ALREADY_MEMBER_OF_HOUSEHOLD_MESSAGE) .errorCode(INDIVIDUAL_ALREADY_MEMBER_OF_HOUSEHOLD) diff --git a/health-services/household/src/main/java/org/egov/household/repository/HouseholdMemberRepository.java b/health-services/household/src/main/java/org/egov/household/repository/HouseholdMemberRepository.java index 565a076eeef..c402d24c05e 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/HouseholdMemberRepository.java +++ b/health-services/household/src/main/java/org/egov/household/repository/HouseholdMemberRepository.java @@ -1,9 +1,14 @@ package org.egov.household.repository; import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.builder.GenericQueryBuilder; +import org.egov.common.data.query.builder.QueryFieldChecker; import org.egov.common.data.query.builder.SelectQueryBuilder; +import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.household.HouseholdMember; +import org.egov.common.models.household.HouseholdMemberSearch; import org.egov.common.producer.Producer; import org.egov.household.repository.rowmapper.HouseholdMemberRowMapper; import org.springframework.beans.factory.annotation.Autowired; @@ -19,6 +24,7 @@ import java.util.Optional; import java.util.stream.Collectors; +import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; import static org.egov.common.utils.CommonUtils.getIdMethod; @Repository @@ -34,7 +40,56 @@ protected HouseholdMemberRepository(Producer producer, super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, householdMemberRowMapper, Optional.of("household_member")); } - public List findById(List ids, String columnName, Boolean includeDeleted) { + + public SearchResponse find(HouseholdMemberSearch householdMemberSearch, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) { + + Map paramsMap = new HashMap<>(); + StringBuilder queryBuilder = new StringBuilder(); + + String query = "SELECT * FROM household_member"; + + List whereFields = GenericQueryBuilder.getFieldsWithCondition(householdMemberSearch, QueryFieldChecker.isNotNull, paramsMap); + query = GenericQueryBuilder.generateQuery(query, whereFields).toString().trim(); + + query = query + " AND tenantId=:tenantId "; + + if (query.contains(this.tableName + " AND")) { + query = query.replace(this.tableName + " AND", this.tableName + " WHERE"); + } + + queryBuilder.append(query); + + if (Boolean.FALSE.equals(includeDeleted)) { + queryBuilder.append("AND isDeleted=:isDeleted "); + } + + if (lastChangedSince != null) { + queryBuilder.append("AND lastModifiedTime>=:lastModifiedTime "); + } + + paramsMap.put("tenantId", tenantId); + paramsMap.put("isDeleted", includeDeleted); + paramsMap.put("lastModifiedTime", lastChangedSince); + + queryBuilder.append(" ORDER BY id ASC "); + + Long totalCount = constructTotalCountCTEAndReturnResult(queryBuilder.toString(), paramsMap, this.namedParameterJdbcTemplate); + + queryBuilder.append(" LIMIT :limit OFFSET :offset"); + paramsMap.put("limit", limit); + paramsMap.put("offset", offset); + + List householdMembers = this.namedParameterJdbcTemplate.query(queryBuilder.toString(), paramsMap, this.rowMapper); + + return SearchResponse.builder().totalCount(totalCount).response(householdMembers).build(); + } + + public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { List objFound = findInCache(ids).stream() .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) .collect(Collectors.toList()); @@ -45,7 +100,7 @@ public List findById(List ids, String columnName, Boole .collect(Collectors.toList())); if (ids.isEmpty()) { log.info("all objects were found in the cache, returning objects"); - return objFound; + return SearchResponse.builder().response(objFound).build(); } } @@ -59,23 +114,29 @@ public List findById(List ids, String columnName, Boole objFound.addAll(this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper)); putInCache(objFound); log.info("returning objects from the database"); - return objFound; + return SearchResponse.builder().response(objFound).build(); } - public List findIndividual(String individualId) { + public SearchResponse findIndividual(String individualId) { log.info("searching for HouseholdMember with individualId: {}", individualId); String query = "SELECT * FROM household_member where individualId = :individualId AND isDeleted = false"; Map paramMap = new HashMap(); paramMap.put("individualId", individualId); - return this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + List householdMembers = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + return SearchResponse.builder().totalCount(Long.valueOf(householdMembers.size())).response(householdMembers).build(); } - public List findIndividualByHousehold(String householdId, String columnName) { + public SearchResponse findIndividualByHousehold(String householdId, String columnName) { log.info("searching for HouseholdMembers with householdId: {}", householdId); String query = String.format("SELECT * FROM household_member where %s = :householdId AND isDeleted = false", columnName); Map paramMap = new HashMap(); paramMap.put("householdId", householdId); - return this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramMap, this.namedParameterJdbcTemplate); + + List householdMembers = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + + return SearchResponse.builder().totalCount(totalCount).response(householdMembers).build(); } } diff --git a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java index 6b98b89cb5b..55a0cee69e1 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java +++ b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java @@ -6,14 +6,16 @@ import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.household.Household; import org.egov.common.producer.Producer; import org.egov.household.repository.rowmapper.HouseholdRowMapper; -import org.egov.household.web.models.HouseholdSearch; +import org.egov.common.models.household.HouseholdSearch; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; import java.lang.reflect.Method; @@ -23,56 +25,70 @@ import java.util.Optional; import java.util.stream.Collectors; +import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; import static org.egov.common.utils.CommonUtils.getIdMethod; @Repository @Slf4j public class HouseholdRepository extends GenericRepository { + private final String searchCriteriaWaypointQuery = "WITH cte_search_criteria_waypoint(s_latitude, s_longitude) AS (VALUES(:s_latitude, :s_longitude))\n"; + private final String calculateDistanceFromTwoWaypointsFormulaQuery = "( 6371.4 * acos (LEAST (GREATEST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) ) + sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), -1), 1) ) ) AS distance "; @Autowired protected HouseholdRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, HouseholdRowMapper householdRowMapper) { - super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, householdRowMapper, Optional.of("household")); + super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, householdRowMapper, Optional.of("household h")); } - public List findById(List ids, String columnName, Boolean includeDeleted) { - List objFound = findInCache(ids).stream() - .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) - .collect(Collectors.toList()); + public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { + List objFound = findInCache(ids); + if (!includeDeleted) { + objFound = objFound.stream() + .filter(entity -> entity.getIsDeleted().equals(false)) + .collect(Collectors.toList()); + } if (!objFound.isEmpty()) { Method idMethod = getIdMethod(objFound, columnName); ids.removeAll(objFound.stream() .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) .collect(Collectors.toList())); if (ids.isEmpty()) { - return objFound; + return SearchResponse.builder().totalCount(Long.valueOf(objFound.size())).response(objFound).build(); } } - String query = String.format("SELECT * FROM household h LEFT JOIN address a ON h.addressid = a.id WHERE h.%s IN (:ids) AND isDeleted = false", columnName); + String query = String.format("SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM household h LEFT JOIN address a ON h.addressid = a.id WHERE h.%s IN (:ids) AND isDeleted = false", columnName); if (null != includeDeleted && includeDeleted) { - query = String.format("SELECT * FROM household h LEFT JOIN address a ON h.addressid = a.id WHERE h.%s IN (:ids)", columnName); + query = String.format("SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM household h LEFT JOIN address a ON h.addressid = a.id WHERE h.%s IN (:ids)", columnName); } Map paramMap = new HashMap(); paramMap.put("ids", ids); + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramMap, this.namedParameterJdbcTemplate); + objFound.addAll(this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper)); putInCache(objFound); - return objFound; + return SearchResponse.builder().totalCount(totalCount).response(objFound).build(); } - public List find(HouseholdSearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { - String query = "SELECT * FROM household h LEFT JOIN address a ON h.addressid = a.id"; + public SearchResponse find(HouseholdSearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) { + String query = "SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid"; + query += " FROM household h LEFT JOIN address a ON h.addressid = a.id"; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); query = query.replace("id IN (:id)", "h.id IN (:id)"); query = query.replace("clientReferenceId IN (:clientReferenceId)", "h.clientReferenceId IN (:clientReferenceId)"); - query = query + " and h.tenantId=:tenantId "; + if(CollectionUtils.isEmpty(whereFields)) { + query = query + " where h.tenantId=:tenantId "; + } else { + query = query + " and h.tenantId=:tenantId "; + } + if (Boolean.FALSE.equals(includeDeleted)) { query = query + "and isDeleted=:isDeleted "; } @@ -80,12 +96,63 @@ public List find(HouseholdSearch searchObject, Integer limit, Integer if (lastChangedSince != null) { query = query + "and lastModifiedTime>=:lastModifiedTime "; } - query = query + "ORDER BY h.id ASC LIMIT :limit OFFSET :offset"; paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); paramsMap.put("lastModifiedTime", lastChangedSince); + + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + + query = query + "ORDER BY h.id ASC LIMIT :limit OFFSET :offset"; + paramsMap.put("limit", limit); + paramsMap.put("offset", offset); + List households = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + return SearchResponse.builder().totalCount(totalCount).response(households).build(); + } + + /** + * @param searchObject + * @param limit + * @param offset + * @param tenantId + * @param includeDeleted + * @return + * @throws QueryBuilderException + * + * Fetch all the household which falls under the radius provided using longitude and latitude provided. + */ + public SearchResponse findByRadius(HouseholdSearch searchObject, Integer limit, Integer offset, String tenantId, Boolean includeDeleted) throws QueryBuilderException { + String query = searchCriteriaWaypointQuery + + "SELECT * FROM (SELECT h.*, a.*, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid, " + calculateDistanceFromTwoWaypointsFormulaQuery + " \n" + + "FROM public.household h LEFT JOIN public.address a ON h.addressid = a.id AND h.tenantid = a.tenantid, cte_search_criteria_waypoint cte_scw "; + Map paramsMap = new HashMap<>(); + List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); + query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); + query = query.replace("id IN (:id)", "h.id IN (:id)"); + query = query.replace("clientReferenceId IN (:clientReferenceId)", "h.clientReferenceId IN (:clientReferenceId)"); + + if(CollectionUtils.isEmpty(whereFields)) { + query = query + " where h.tenantId=:tenantId "; + } else { + query = query + " and h.tenantId=:tenantId "; + } + + if (Boolean.FALSE.equals(includeDeleted)) { + query = query + "and isDeleted=:isDeleted "; + } + query = query + " ) AS rt "; + query = query + " WHERE distance < :distance "; + paramsMap.put("s_latitude", searchObject.getLatitude()); + paramsMap.put("s_longitude", searchObject.getLongitude()); + paramsMap.put("tenantId", tenantId); + paramsMap.put("isDeleted", includeDeleted); + paramsMap.put("distance", searchObject.getSearchRadius()); + query = query + " ORDER BY distance ASC"; + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + query = query + " LIMIT :limit OFFSET :offset "; paramsMap.put("limit", limit); paramsMap.put("offset", offset); - return this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + List households = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + return SearchResponse.builder().totalCount(totalCount).response(households).build(); } + } diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java index a306509a3c4..79a762807ea 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java @@ -1,16 +1,16 @@ package org.egov.household.repository.rowmapper; +import java.sql.ResultSet; +import java.sql.SQLException; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.household.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.household.HouseholdMember; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import java.sql.ResultSet; -import java.sql.SQLException; - @Component public class HouseholdMemberRowMapper implements RowMapper { private final ObjectMapper objectMapper = new ObjectMapper(); @@ -18,9 +18,22 @@ public class HouseholdMemberRowMapper implements RowMapper { @Override public HouseholdMember mapRow(ResultSet resultSet, int i) throws SQLException { try { + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) + .build(); return HouseholdMember.builder() .id(resultSet.getString("id")) .householdId(resultSet.getString("householdId")) + .clientReferenceId(resultSet.getString("clientReferenceId")) .householdClientReferenceId(resultSet.getString("householdClientReferenceId")) .individualClientReferenceId(resultSet.getString("individualClientReferenceId")) .individualId(resultSet.getString("individualId")) @@ -30,12 +43,8 @@ public HouseholdMember mapRow(ResultSet resultSet, int i) throws SQLException { .getString("additionalDetails"), AdditionalFields.class)) .isDeleted(resultSet.getBoolean("isDeleted")) .rowVersion(resultSet.getInt("rowVersion")) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) .build(); } catch (JsonProcessingException e) { throw new SQLException(e); diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java index 6d79b983220..be08e68e1d1 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java @@ -1,19 +1,19 @@ package org.egov.household.repository.rowmapper; +import java.sql.ResultSet; +import java.sql.SQLException; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.household.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.household.Address; import org.egov.common.models.household.AddressType; -import org.egov.common.models.household.Boundary; +import org.egov.common.models.core.Boundary; import org.egov.common.models.household.Household; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import java.sql.ResultSet; -import java.sql.SQLException; - @Component public class HouseholdRowMapper implements RowMapper { private final ObjectMapper objectMapper = new ObjectMapper(); @@ -21,25 +21,33 @@ public class HouseholdRowMapper implements RowMapper { @Override public Household mapRow(ResultSet resultSet, int i) throws SQLException { try { - return Household.builder() + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) + .build(); + Household household = Household.builder() .id(resultSet.getString("id")) .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) .tenantId(resultSet.getString("tenantId")) .memberCount(resultSet.getInt("numberOfMembers")) .clientReferenceId(resultSet.getString("clientReferenceId")) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet .getString("additionalDetails"), AdditionalFields.class)) .address(Address.builder() - .id(resultSet.getString(13)) - .clientReferenceId(resultSet.getString(28)) - .tenantId(resultSet.getString(14)) + .id(resultSet.getString("aid")) + .clientReferenceId(resultSet.getString("aclientreferenceid")) + .tenantId(resultSet.getString("atenantid")) .doorNo(resultSet.getString("doorNo")) .latitude(resultSet.getDouble("latitude")) .longitude(resultSet.getDouble("longitude")) @@ -52,9 +60,14 @@ public Household mapRow(ResultSet resultSet, int i) throws SQLException { .pincode(resultSet.getString("pinCode")) .buildingName(resultSet.getString("buildingName")) .street(resultSet.getString("street")) - .locality(Boundary.builder().code(resultSet.getString("localityCode")).build()) + .locality(resultSet.getString("localityCode") != null ? + Boundary.builder().code(resultSet.getString("localityCode")).build() : null) .build()) .build(); + if (household.getAddress().getId() == null) { + household.setAddress(null); + } + return household; } catch (JsonProcessingException e) { throw new SQLException(e); } diff --git a/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberEnrichmentService.java b/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberEnrichmentService.java index d1943070ba8..ed07e4c8135 100644 --- a/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberEnrichmentService.java +++ b/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberEnrichmentService.java @@ -58,7 +58,7 @@ public void update(List householdMembers, Map hMap = getIdToObjMap(householdMembers); List householdMemberIds = new ArrayList<>(hMap.keySet()); List existingHouseholdMembers = householdMemberRepository.findById(householdMemberIds, - "id", false); + "id", false).getResponse(); log.info("updating lastModifiedTime and lastModifiedBy"); enrichForUpdate(hMap, existingHouseholdMembers, beneficiaryRequest); log.info("household Members updated successfully."); @@ -72,7 +72,7 @@ public void enrichHousehold(List householdMembers) { log.info("getting houseHoldIds for householdMembers"); List houseHoldIds = getIdList(householdMembers, idMethod); log.info("finding households from householdService with ids: {}", houseHoldIds); - List householdList = householdService.findById(houseHoldIds, columnName, false); + List householdList = householdService.findById(houseHoldIds, columnName, false).getResponse(); log.info("getting method for householdList with columnName: {}", columnName); Method householdMethod = getIdMethod(householdList, columnName); log.info("getting Map of households"); diff --git a/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberService.java b/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberService.java index c1621e432cf..9d64577f1f9 100644 --- a/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberService.java +++ b/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberService.java @@ -1,16 +1,26 @@ package org.egov.household.service; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.ds.Tuple; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.household.HouseholdMember; import org.egov.common.models.household.HouseholdMemberBulkRequest; import org.egov.common.models.household.HouseholdMemberRequest; +import org.egov.common.models.household.HouseholdMemberSearch; import org.egov.common.utils.CommonUtils; import org.egov.common.validator.Validator; import org.egov.household.config.HouseholdMemberConfiguration; +import org.egov.household.household.member.validators.HmExistentEntityValidator; import org.egov.household.household.member.validators.HmHouseholdHeadValidator; import org.egov.household.household.member.validators.HmHouseholdValidator; import org.egov.household.household.member.validators.HmIndividualValidator; @@ -21,18 +31,11 @@ import org.egov.household.household.member.validators.HmUniqueEntityValidator; import org.egov.household.household.member.validators.HmUniqueIndividualValidator; import org.egov.household.repository.HouseholdMemberRepository; -import org.egov.household.web.models.HouseholdMemberSearch; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdMethod; import static org.egov.common.utils.CommonUtils.handleErrors; @@ -73,6 +76,7 @@ public class HouseholdMemberService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(HmHouseholdValidator.class) + || validator.getClass().equals(HmExistentEntityValidator.class) || validator.getClass().equals(HmUniqueIndividualValidator.class) || validator.getClass().equals(HmHouseholdHeadValidator.class); @@ -124,7 +128,7 @@ public List create(HouseholdMemberBulkRequest householdMemberBu log.info("household members data saved successfully"); } } catch (Exception exception) { - log.error("error occurred while creating household members: ", exception); + log.error("error occurred while creating household members: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(householdMemberBulkRequest, errorDetailsMap, validHouseholdMembers, exception, SET_HOUSEHOLD_MEMBERS); } @@ -134,28 +138,32 @@ public List create(HouseholdMemberBulkRequest householdMemberBu } - public List search(HouseholdMemberSearch householdMemberSearch, Integer limit, Integer offset, String tenantId, - Long lastChangedSince, Boolean includeDeleted) { + public SearchResponse search(HouseholdMemberSearch householdMemberSearch, Integer limit, Integer offset, String tenantId, + Long lastChangedSince, Boolean includeDeleted) { String idFieldName = getIdFieldName(householdMemberSearch); if (isSearchByIdOnly(householdMemberSearch, idFieldName)) { List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections .singletonList(householdMemberSearch)), householdMemberSearch); - List householdMembers = householdMemberRepository.findById(ids, - idFieldName, includeDeleted).stream() + SearchResponse searchResponse = householdMemberRepository.findById(ids, + idFieldName, includeDeleted); + List householdMembers = searchResponse.getResponse().stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); log.info("found {} household members for search by id", householdMembers.size()); - return householdMembers; + + searchResponse.setResponse(householdMembers); + + return searchResponse; } try { return householdMemberRepository.find(householdMemberSearch, limit, offset, tenantId, lastChangedSince, includeDeleted); - } catch (QueryBuilderException e) { - log.error("error in building query for household member search", e); + } catch (Exception e) { + log.error("error in building query for household member search: {}", ExceptionUtils.getStackTrace(e)); throw new CustomException("ERROR_IN_QUERY", e.getMessage()); } } @@ -186,7 +194,7 @@ public List update(HouseholdMemberBulkRequest householdMemberBu log.info("household member data updated successfully"); } } catch (Exception exception) { - log.error("error occurred", exception); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(householdMemberBulkRequest, errorDetailsMap, validHouseholdMembers, exception, SET_HOUSEHOLD_MEMBERS); } @@ -218,7 +226,7 @@ public List delete(HouseholdMemberBulkRequest householdMemberBu log.info("deleted Household Members: {}", validHouseholdMembers); } } catch (Exception exception) { - log.error("error occurred while deleting household members", exception); + log.error("error occurred while deleting household members: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(householdMemberBulkRequest, errorDetailsMap, validHouseholdMembers, exception, SET_HOUSEHOLD_MEMBERS); } diff --git a/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java b/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java index feada174cd4..c6f701b6eb0 100644 --- a/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java +++ b/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java @@ -1,9 +1,11 @@ package org.egov.household.service; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdBulkRequest; import org.egov.common.models.household.HouseholdRequest; @@ -12,12 +14,14 @@ import org.egov.common.validator.Validator; import org.egov.household.config.HouseholdConfiguration; import org.egov.household.repository.HouseholdRepository; +import org.egov.household.validators.household.HExistentEntityValidator; +import org.egov.household.validators.household.HBoundaryValidator; import org.egov.household.validators.household.HIsDeletedValidator; -import org.egov.household.validators.household.HNonExsistentEntityValidator; +import org.egov.household.validators.household.HNonExistentEntityValidator; import org.egov.household.validators.household.HNullIdValidator; import org.egov.household.validators.household.HRowVersionValidator; import org.egov.household.validators.household.HUniqueEntityValidator; -import org.egov.household.web.models.HouseholdSearch; +import org.egov.common.models.household.HouseholdSearch; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -56,16 +60,21 @@ public class HouseholdService { private final HouseholdEnrichmentService enrichmentService; + private final Predicate> isApplicableForCreate = validator -> + validator.getClass().equals(HBoundaryValidator.class) + || validator.getClass().equals(HExistentEntityValidator.class); + private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(HNullIdValidator.class) + || validator.getClass().equals(HBoundaryValidator.class) || validator.getClass().equals(HIsDeletedValidator.class) || validator.getClass().equals(HUniqueEntityValidator.class) - || validator.getClass().equals(HNonExsistentEntityValidator.class) + || validator.getClass().equals(HNonExistentEntityValidator.class) || validator.getClass().equals(HRowVersionValidator.class); private final Predicate> isApplicableForDelete = validator -> validator.getClass().equals(HNullIdValidator.class) - || validator.getClass().equals(HNonExsistentEntityValidator.class) + || validator.getClass().equals(HNonExistentEntityValidator.class) || validator.getClass().equals(HRowVersionValidator.class); @Autowired @@ -91,8 +100,11 @@ public Household create(HouseholdRequest request) { public List create(HouseholdBulkRequest request, boolean isBulk) { log.info("received request to create households"); - Map errorDetailsMap = new HashMap<>(); - List validEntities = request.getHouseholds(); + Tuple, Map> tuple = validate(validators, + isApplicableForCreate, request, + isBulk); + Map errorDetailsMap = tuple.getY(); + List validEntities = tuple.getX(); try { if (!validEntities.isEmpty()) { enrichmentService.create(validEntities, request); @@ -100,7 +112,7 @@ public List create(HouseholdBulkRequest request, boolean isBulk) { log.info("successfully created {} households", validEntities.size()); } } catch (Exception exception) { - log.error("error occurred while creating households", exception); + log.error("error occurred while creating households: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_HOUSEHOLDS); } @@ -108,30 +120,35 @@ public List create(HouseholdBulkRequest request, boolean isBulk) { return request.getHouseholds(); } - public List search(HouseholdSearch householdSearch, Integer limit, Integer offset, String tenantId, - Long lastChangedSince, Boolean includeDeleted) { + public SearchResponse search(HouseholdSearch householdSearch, Integer limit, Integer offset, String tenantId, + Long lastChangedSince, Boolean includeDeleted) { String idFieldName = getIdFieldName(householdSearch); if (isSearchByIdOnly(householdSearch, idFieldName)) { List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections .singletonList(householdSearch)), householdSearch); - List households = householdRepository.findById(ids, - idFieldName, includeDeleted).stream() + SearchResponse householdsTuple = householdRepository.findById(ids, + idFieldName, includeDeleted); + List households = householdsTuple.getResponse().stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); log.info("households found for search by id, size: {}", households.size()); - return households; + return SearchResponse.builder().totalCount(Long.valueOf(households.size())).response(households).build(); } try { - List households = householdRepository.find(householdSearch, limit, offset, - tenantId, lastChangedSince, includeDeleted); - log.info("households found for search, size: {}", households.size()); - return households; + SearchResponse searchResponse; + if(Boolean.TRUE.equals(isProximityBasedSearch(householdSearch))) { + searchResponse = householdRepository.findByRadius(householdSearch, limit, offset, tenantId, includeDeleted); + } else { + searchResponse = householdRepository.find(householdSearch, limit, offset, tenantId, lastChangedSince, includeDeleted); + } + log.info("households found for search, size: {}", searchResponse.getResponse().size()); + return searchResponse; } catch (QueryBuilderException e) { - log.error("error occurred while searching households", e); + log.error("error occurred while searching households: {}", ExceptionUtils.getStackTrace(e)); throw new CustomException("ERROR_IN_QUERY", e.getMessage()); } } @@ -157,7 +174,7 @@ public List update(HouseholdBulkRequest request, boolean isBulk) { log.info("successfully updated households"); } } catch (Exception exception) { - log.error("error occurred while updating households: " + exception.getMessage()); + log.error("error occurred while updating households: {}" , ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_HOUSEHOLDS); } @@ -191,7 +208,7 @@ public List delete(HouseholdBulkRequest request, boolean isBulk) { log.info("Households saved to delete topic"); } } catch (Exception exception) { - log.error("error occurred while deleting households: ", exception); + log.error("error occurred while deleting households: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_HOUSEHOLDS); } @@ -199,13 +216,13 @@ public List delete(HouseholdBulkRequest request, boolean isBulk) { return request.getHouseholds(); } - public List findById(List houseHoldIds, String columnName, boolean includeDeleted){ + public SearchResponse findById(List houseHoldIds, String columnName, boolean includeDeleted){ log.info("finding Households by Ids: {} with columnName: {} and includeDeleted: {}", houseHoldIds, columnName, includeDeleted); log.info("started finding Households by Ids"); - List households = householdRepository.findById(houseHoldIds, columnName, includeDeleted); - log.info("finished finding Households by Ids. Found {} Households", households.size()); - return households; + SearchResponse searchResponse = householdRepository.findById(houseHoldIds, columnName, includeDeleted); + log.info("finished finding Households by Ids. Found {} Households", searchResponse.getResponse().size()); + return searchResponse; } public void putInCache(List households) { @@ -231,4 +248,7 @@ private Tuple, Map> validate(List(validHouseholds, errorDetailsMap); } + private Boolean isProximityBasedSearch(HouseholdSearch householdSearch) { + return householdSearch.getLatitude() != null && householdSearch.getLongitude() != null && householdSearch.getSearchRadius() != null; + } } diff --git a/health-services/household/src/main/java/org/egov/household/service/IndividualService.java b/health-services/household/src/main/java/org/egov/household/service/IndividualService.java index 5701e87c5a1..369dfb9b1fd 100644 --- a/health-services/household/src/main/java/org/egov/household/service/IndividualService.java +++ b/health-services/household/src/main/java/org/egov/household/service/IndividualService.java @@ -1,6 +1,7 @@ package org.egov.household.service; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; @@ -82,7 +83,7 @@ private IndividualBulkResponse getIndividualResponse(String tenantId, Individual individualSearchRequest, IndividualBulkResponse.class); } catch (Exception e) { - log.error("error while fetching individuals list: {}", e.getMessage()); + log.error("error while fetching individuals list: {}", ExceptionUtils.getStackTrace(e)); throw new CustomException(INTERNAL_SERVER_ERROR, "Error while fetching individuals list"); } } diff --git a/health-services/household/src/main/java/org/egov/household/validators/household/HBoundaryValidator.java b/health-services/household/src/main/java/org/egov/household/validators/household/HBoundaryValidator.java new file mode 100644 index 00000000000..a92ad1aad3e --- /dev/null +++ b/health-services/household/src/main/java/org/egov/household/validators/household/HBoundaryValidator.java @@ -0,0 +1,127 @@ +package org.egov.household.validators.household; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.core.Boundary; +import org.egov.common.models.household.Household; +import org.egov.common.models.household.HouseholdBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.household.config.HouseholdConfiguration; +import org.egov.household.web.models.boundary.BoundaryResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +/** + * Validator class for validating household boundaries. + */ +@Component +@Order(value = 4) +@Slf4j +public class HBoundaryValidator implements Validator { + + private final ServiceRequestClient serviceRequestClient; + + private final HouseholdConfiguration householdConfiguration; + + /** + * Constructor to initialize the HBoundaryValidator. + * + * @param serviceRequestClient Service request client for making HTTP requests + * @param householdConfiguration Configuration properties for the household module + */ + public HBoundaryValidator(ServiceRequestClient serviceRequestClient, HouseholdConfiguration householdConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.householdConfiguration = householdConfiguration; + } + + /** + * Validates the households' boundaries. + * + * @param request the bulk request containing households + * @return a map containing households with their corresponding list of errors + */ + @Override + public Map> validate(HouseholdBulkRequest request) { + log.debug("Validating households boundaries."); + // Create a HashMap to store error details for each household + HashMap> errorDetailsMap = new HashMap<>(); + + // Filter households with non-null addresses + List entitiesWithValidBoundaries = request.getHouseholds().parallelStream() + .filter(household -> Objects.nonNull(household.getAddress())) + .filter(household -> Objects.nonNull(household.getAddress().getLocality())) // Exclude null locality codes + .collect(Collectors.toList()); + + Map> tenantIdHouseholdMap = entitiesWithValidBoundaries.stream().collect(Collectors.groupingBy(Household::getTenantId)); + + tenantIdHouseholdMap.forEach((tenantId, households) -> { + // Group households by locality code + Map> boundaryCodeHouseholdsMap = households.stream() + .collect(Collectors.groupingBy( + household -> household.getAddress().getLocality().getCode() // Group by locality code + )); + + List boundaries = new ArrayList<>(boundaryCodeHouseholdsMap.keySet()); + if(!CollectionUtils.isEmpty(boundaries)) { + try { + // Fetch boundary details from the service + log.debug("Fetching boundary details for tenantId: {}, boundaries: {}", tenantId, boundaries); + BoundaryResponse boundarySearchResponse = serviceRequestClient.fetchResult( + new StringBuilder(householdConfiguration.getBoundaryServiceHost() + + householdConfiguration.getBoundarySearchUrl() + +"?limit=" + boundaries.size() + + "&offset=0&tenantId=" + tenantId + + "&codes=" + String.join(",", boundaries)), + request.getRequestInfo(), + BoundaryResponse.class + ); + log.debug("Boundary details fetched successfully for tenantId: {}", tenantId); + + List invalidBoundaryCodes = new ArrayList<>(boundaries); + invalidBoundaryCodes.removeAll(boundarySearchResponse.getBoundary().stream() + .map(Boundary::getCode) + .collect(Collectors.toList()) + ); + + // Filter out households with invalid boundary codes + List householdsWithInvalidBoundaries = boundaryCodeHouseholdsMap.entrySet().stream() + .filter(entry -> invalidBoundaryCodes.contains(entry.getKey())) // filter invalid boundary codes + .flatMap(entry -> entry.getValue().stream()) // Flatten the list of households + .collect(Collectors.toList()); + + + householdsWithInvalidBoundaries.forEach(household -> { + // Create an error object for households with invalid boundaries + Error error = Error.builder() + .errorMessage("Boundary code does not exist in db") + .errorCode("NON_EXISTENT_ENTITY") + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException("NON_EXISTENT_ENTITY", "Boundary code does not exist in db")) + .build(); + // Populate error details for the household + populateErrorDetails(household, error, errorDetailsMap); + }); + + } catch (Exception e) { + log.error("Exception while searching boundaries for tenantId: {}", tenantId, e); + // Throw a custom exception if an error occurs during boundary search + throw new CustomException("BOUNDARY_SERVICE_SEARCH_ERROR","Error in while fetching boundaries from Boundary Service : " + e.getMessage()); + } + } + }); + + return errorDetailsMap; + } +} diff --git a/health-services/household/src/main/java/org/egov/household/validators/household/HExistentEntityValidator.java b/health-services/household/src/main/java/org/egov/household/validators/household/HExistentEntityValidator.java new file mode 100644 index 00000000000..33253089919 --- /dev/null +++ b/health-services/household/src/main/java/org/egov/household/validators/household/HExistentEntityValidator.java @@ -0,0 +1,97 @@ +package org.egov.household.validators.household; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.household.Household; +import org.egov.common.models.household.HouseholdBulkRequest; +import org.egov.common.models.household.HouseholdSearch; +import org.egov.common.validator.Validator; +import org.egov.household.repository.HouseholdRepository; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of entities with the given client reference IDs. + * This validator checks if the provided household entities already exist in the database based on their client reference IDs. + * + * @author kanishq-egov + */ +@Component +@Order(value = 1) +@Slf4j +public class HExistentEntityValidator implements Validator { + + private final HouseholdRepository householdRepository; + + /** + * Constructor to initialize the HouseholdRepository dependency. + * + * @param householdRepository The repository for household entities. + */ + public HExistentEntityValidator(HouseholdRepository householdRepository) { + this.householdRepository = householdRepository; + } + + /** + * Validates the existence of entities with the given client reference IDs. + * This method checks if any of the household entities in the request already exist in the database, + * based on their client reference IDs. If an entity is found to exist, an error is added to the error details map. + * + * @param request The bulk request containing household entities. + * @return A map containing household entities and their associated error details, if any. + */ + @Override + public Map> validate(HouseholdBulkRequest request) { + // Map to hold household entities and their associated error details + Map> errorDetailsMap = new HashMap<>(); + + // Get the list of household entities from the request + List entities = request.getHouseholds(); + + // Extract client reference IDs from household entities that do not have errors + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) // Filter out entities that already have errors + .map(Household::getClientReferenceId) // Map to client reference IDs + .collect(Collectors.toList()); // Collect the IDs into a list + + // Create a map of client reference ID to Household entity for easy lookup + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + + // Create a search object for querying entities by client reference IDs + HouseholdSearch householdSearch = HouseholdSearch.builder() + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search + .build(); + + // Check if the client reference ID list is not empty before querying the database + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing entities by client reference IDs + List existingClientReferenceIds = + householdRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, populate error details for uniqueness + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation + Error error = getErrorForUniqueEntity(); + // Populate error details for the household entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); + }); + } + + // Return the map containing household entities and their associated error details + return errorDetailsMap; + } + +} diff --git a/health-services/household/src/main/java/org/egov/household/validators/household/HNonExistentEntityValidator.java b/health-services/household/src/main/java/org/egov/household/validators/household/HNonExistentEntityValidator.java new file mode 100644 index 00000000000..f6a3a129f31 --- /dev/null +++ b/health-services/household/src/main/java/org/egov/household/validators/household/HNonExistentEntityValidator.java @@ -0,0 +1,107 @@ +package org.egov.household.validators.household; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.models.Error; +import org.egov.common.models.household.Household; +import org.egov.common.models.household.HouseholdBulkRequest; +import org.egov.common.models.household.HouseholdSearch; +import org.egov.common.validator.Validator; +import org.egov.household.repository.HouseholdRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; +import static org.egov.household.Constants.GET_ID; + +/** + * Validator for checking the non-existence of household entities. + * This validator checks if the provided household entities do not already exist in the database. + * + * @author kanishq-egov + */ +@Component +@Order(value = 2) +@Slf4j +public class HNonExistentEntityValidator implements Validator { + + private final HouseholdRepository householdRepository; + + public HNonExistentEntityValidator(HouseholdRepository householdRepository) { + this.householdRepository = householdRepository; + } + + /** + * Validates the non-existence of entities based on their IDs and client reference IDs. + * + * @param request The bulk request containing household entities. + * @return A map containing household entities and their associated error details. + */ + @Override + public Map> validate(HouseholdBulkRequest request) { + // Map to hold household entities and their error details + Map> errorDetailsMap = new HashMap<>(); + // Get the list of household entities from the request + List entities = request.getHouseholds(); + // Get the class of the household entity + Class objClass = getObjClass(entities); + // Get the method for fetching the ID of the entity + Method idMethod = getMethod(GET_ID, objClass); + // Map to store entities by their IDs + Map eMap = getIdToObjMap( + entities.stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + // Lists to store IDs and client reference IDs + List idList = new ArrayList<>(); + List clientReferenceIdList = new ArrayList<>(); + // Extract IDs and client reference IDs from household entities + entities.forEach(household -> { + idList.add(household.getId()); + clientReferenceIdList.add(household.getClientReferenceId()); + }); + // Check if the entity map is not empty + if (!eMap.isEmpty()) { + // Extract entity IDs + List entityIds = new ArrayList<>(eMap.keySet()); + // Create a search object for querying existing entities + HouseholdSearch householdSearch = HouseholdSearch.builder() + .clientReferenceId(clientReferenceIdList) + .id(idList) + .build(); + + List existingEntities; + try { + // Query the repository to find existing entities + existingEntities = householdRepository.find(householdSearch, entities.size(), 0, + entities.get(0).getTenantId(), null, false).getResponse(); + } catch (Exception e) { + // Handle query builder exception + log.error("Search failed for Household with error: {}", e.getMessage(), e); + throw new CustomException("HOUSEHOLD_SEARCH_FAILED", "Search Failed for Household, " + e.getMessage()); + } + // Check for non-existent entities + List nonExistentEntities = checkNonExistentEntities(eMap, + existingEntities, idMethod); + // Populate error details for non-existent entities + nonExistentEntities.forEach(entity -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + + return errorDetailsMap; + } +} diff --git a/health-services/household/src/main/java/org/egov/household/validators/household/HNonExsistentEntityValidator.java b/health-services/household/src/main/java/org/egov/household/validators/household/HNonExsistentEntityValidator.java index 2ae5f41b4f5..2458f465b66 100644 --- a/health-services/household/src/main/java/org/egov/household/validators/household/HNonExsistentEntityValidator.java +++ b/health-services/household/src/main/java/org/egov/household/validators/household/HNonExsistentEntityValidator.java @@ -48,7 +48,7 @@ public Map> validate(HouseholdBulkRequest request) { if (!eMap.isEmpty()) { List entityIds = new ArrayList<>(eMap.keySet()); List existingEntities = householdRepository.findById(entityIds, - getIdFieldName(idMethod), false); + getIdFieldName(idMethod), false).getResponse(); List nonExistentEntities = checkNonExistentEntities(eMap, existingEntities, idMethod); nonExistentEntities.forEach(task -> { diff --git a/health-services/household/src/main/java/org/egov/household/validators/household/HRowVersionValidator.java b/health-services/household/src/main/java/org/egov/household/validators/household/HRowVersionValidator.java index a27dff638c0..8a6e73a9b88 100644 --- a/health-services/household/src/main/java/org/egov/household/validators/household/HRowVersionValidator.java +++ b/health-services/household/src/main/java/org/egov/household/validators/household/HRowVersionValidator.java @@ -45,7 +45,7 @@ public Map> validate(HouseholdBulkRequest request) { if (!eMap.isEmpty()) { List entityIds = new ArrayList<>(eMap.keySet()); List existingEntities = repository.findById(entityIds, - getIdFieldName(idMethod), false); + getIdFieldName(idMethod), false).getResponse(); List entitiesWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(eMap, existingEntities, idMethod); entitiesWithMismatchedRowVersion.forEach(individual -> { diff --git a/health-services/household/src/main/java/org/egov/household/web/controllers/HouseholdApiController.java b/health-services/household/src/main/java/org/egov/household/web/controllers/HouseholdApiController.java index d37a560f8bb..82e3263f2fb 100644 --- a/health-services/household/src/main/java/org/egov/household/web/controllers/HouseholdApiController.java +++ b/health-services/household/src/main/java/org/egov/household/web/controllers/HouseholdApiController.java @@ -1,9 +1,15 @@ package org.egov.household.web.controllers; +import java.util.List; + import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdBulkRequest; import org.egov.common.models.household.HouseholdBulkResponse; @@ -12,35 +18,28 @@ import org.egov.common.models.household.HouseholdMemberBulkResponse; import org.egov.common.models.household.HouseholdMemberRequest; import org.egov.common.models.household.HouseholdMemberResponse; +import org.egov.common.models.household.HouseholdMemberSearchRequest; import org.egov.common.models.household.HouseholdRequest; import org.egov.common.models.household.HouseholdResponse; +import org.egov.common.models.household.HouseholdSearchRequest; import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; import org.egov.household.config.HouseholdConfiguration; import org.egov.household.config.HouseholdMemberConfiguration; import org.egov.household.service.HouseholdMemberService; import org.egov.household.service.HouseholdService; -import org.egov.household.web.models.HouseholdMemberSearchRequest; -import org.egov.household.web.models.HouseholdSearchRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.util.List; -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") @Controller @RequestMapping("") @@ -98,14 +97,22 @@ public ResponseEntity householdMemberV1CreatePost(@ApiP } @RequestMapping(value = "/member/v1/_search", method = RequestMethod.POST) - public ResponseEntity householdMemberV1SearchPost(@ApiParam(value = "Details for existing household member.", required = true) @Valid @RequestBody HouseholdMemberSearchRequest householdMemberSearchRequest, @NotNull - @Min(0) - @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull - @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) { - List households = householdMemberService.search(householdMemberSearchRequest.getHouseholdMemberSearch(), limit, offset, tenantId, lastChangedSince, includeDeleted); + public ResponseEntity householdMemberV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Details for existing household member.", required = true) @Valid @RequestBody HouseholdMemberSearchRequest householdMemberSearchRequest + ) { + SearchResponse searchResponse = householdMemberService.search( + householdMemberSearchRequest.getHouseholdMemberSearch(), + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() + ); HouseholdMemberBulkResponse response = HouseholdMemberBulkResponse.builder().responseInfo(ResponseInfoFactory .createResponseInfo(householdMemberSearchRequest.getRequestInfo(), true)) - .householdMembers(households) + .householdMembers(searchResponse.getResponse()) + .totalCount(searchResponse.getTotalCount()) .build(); return ResponseEntity.status(HttpStatus.OK).body(response); @@ -197,16 +204,25 @@ public ResponseEntity householdV1DeletePost(@ApiParam(value = "Cap } @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) - public ResponseEntity householdV1SearchPost(@ApiParam(value = "Details for existing household.", required = true) @Valid @RequestBody HouseholdSearchRequest request, - @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, - @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, - @NotNull @Size(min = 2, max = 1000) @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, - @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, - @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) { - - List households = householdService.search(request.getHousehold(), limit, offset, tenantId, lastChangedSince, includeDeleted); - HouseholdBulkResponse response = HouseholdBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).households(households).build(); + public ResponseEntity householdV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Details for existing household.", required = true) @Valid @RequestBody HouseholdSearchRequest request + ) { + SearchResponse searchResponse = householdService.search( + request.getHousehold(), + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() + ); + HouseholdBulkResponse response = HouseholdBulkResponse.builder() + .responseInfo( + ResponseInfoFactory.createResponseInfo( + request.getRequestInfo(), true + ) + ).totalCount(searchResponse.getTotalCount()) + .households(searchResponse.getResponse()).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdMemberSearch.java b/health-services/household/src/main/java/org/egov/household/web/models/HouseholdMemberSearch.java deleted file mode 100644 index 96be64a0e17..00000000000 --- a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdMemberSearch.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.egov.household.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Table; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import java.util.List; - -/** -* Search model for household member -*/ - @ApiModel(description = "Search model for household member") -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) - @Table(name = "household_member") -public class HouseholdMemberSearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("householdId") - private String householdId = null; - - @JsonProperty("householdClientReferenceId") - private String householdClientReferenceId = null; - - @JsonProperty("individualId") - private String individualId = null; - - @JsonProperty("individualClientReferenceId") - private String individualClientReferenceId = null; - - @JsonProperty("isHeadOfHousehold") - private Boolean isHeadOfHousehold = null; - - @JsonProperty("tenantId") - @Valid - private String tenantId = null; - -} - diff --git a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdMemberSearchRequest.java b/health-services/household/src/main/java/org/egov/household/web/models/HouseholdMemberSearchRequest.java deleted file mode 100644 index f4b82ca9688..00000000000 --- a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdMemberSearchRequest.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.egov.household.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -/** -* HouseholdMemberSearchRequest -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class HouseholdMemberSearchRequest { - - @JsonProperty("RequestInfo") - @NotNull - @Valid - private org.egov.common.contract.request.RequestInfo requestInfo = null; - - @JsonProperty("HouseholdMember") - @NotNull - @Valid - private HouseholdMemberSearch householdMemberSearch = null; - - -} - diff --git a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearch.java b/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearch.java deleted file mode 100644 index 839a161a859..00000000000 --- a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearch.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.egov.household.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Table; -import org.springframework.validation.annotation.Validated; - -import java.util.List; - -/** -* A representation of Household. -*/ - @ApiModel(description = "A representation of Household.") -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -@Table(name = "household h") -public class HouseholdSearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; - -// @JsonProperty("memberCount") -// private Integer memberCount = null; - - @JsonProperty("boundaryCode") - private String localityCode = null; -} - diff --git a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearchRequest.java b/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearchRequest.java deleted file mode 100644 index e55cbc9ff3f..00000000000 --- a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearchRequest.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.egov.household.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.contract.request.RequestInfo; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -/** -* HouseholdSearchRequest -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class HouseholdSearchRequest { - - @JsonProperty("RequestInfo") - @NotNull - @Valid - private RequestInfo requestInfo = null; - - @JsonProperty("Household") - @NotNull - @Valid - private HouseholdSearch household = null; -} - diff --git a/health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundaryRequest.java b/health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundaryRequest.java new file mode 100644 index 00000000000..9b3937ed018 --- /dev/null +++ b/health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundaryRequest.java @@ -0,0 +1,38 @@ +package org.egov.household.web.models.boundary; + +import java.util.List; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryRequest + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @Valid + @NotNull + @JsonProperty("Boundary") + @Size(min = 1, max = 300) + private List boundary = null; + +} diff --git a/health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundaryResponse.java b/health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundaryResponse.java new file mode 100644 index 00000000000..4f3f07f82b9 --- /dev/null +++ b/health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundaryResponse.java @@ -0,0 +1,44 @@ +package org.egov.household.web.models.boundary; + +import java.util.ArrayList; +import java.util.List; +import jakarta.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryResponse + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Boundary") + @Valid + private List boundary = null; + + + public BoundaryResponse addBoundaryItem(Boundary boundaryItem) { + if (this.boundary == null) { + this.boundary = new ArrayList<>(); + } + this.boundary.add(boundaryItem); + return this; + } + +} diff --git a/health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundarySearchCriteria.java b/health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundarySearchCriteria.java new file mode 100644 index 00000000000..f7c6fcca045 --- /dev/null +++ b/health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundarySearchCriteria.java @@ -0,0 +1,37 @@ +package org.egov.household.web.models.boundary; + +import java.util.List; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundarySearchCriteria { + + @NotNull + @Size(min = 1) + @JsonProperty("codes") + private List codes; + + @NotNull + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} diff --git a/health-services/household/src/main/resources/application.properties b/health-services/household/src/main/resources/application.properties index ae3b0272d47..dfd2b4f6937 100644 --- a/health-services/household/src/main/resources/application.properties +++ b/health-services/household/src/main/resources/application.properties @@ -23,7 +23,7 @@ spring.flyway.table=public spring.flyway.baseline-on-migrate=true spring.flyway.outOfOrder=true spring.flyway.locations=classpath:/db/migration/main -spring.flyway.enabled=true +spring.flyway.enabled=false # TRACER CONFIG # KAFKA SERVER CONFIG @@ -49,8 +49,8 @@ kafka.producer.config.linger_ms_config=1 kafka.producer.config.buffer_memory_config=33554432 # IDGEN CONFIG -egov.idgen.host=https://dev.digit.org/ -#egov.idgen.host=http://localhost:8081/ +#egov.idgen.host=https://dev.digit.org/ +egov.idgen.host=http://localhost:8082/ egov.idgen.path=egov-idgen/id/_generate egov.idgen.integration.enabled=true household.idgen.id.format=household.id @@ -59,7 +59,8 @@ household.idgen.id.format=household.id kafka.topics.consumer=household-consumer-topic # USER CONFIG -egov.user.host=https://dev.digit.org +#egov.user.host=https://dev.digit.org +egov.user.host=http://localhost:8083/ egov.user.context.path=/user/users egov.user.create.path=/_createnovalidate egov.user.search.path=/user/_search @@ -96,3 +97,9 @@ household.member.consumer.bulk.delete.topic=household-member-consumer-bulk-delet # INDIVIDUAL SERVICE egov.individual.host=https://dev.digit.org egov.individual.search.url=/individual/v1/_search + + +# BOUNDARY SERVICE +egov.boundary.host=http://localhost:8081 +egov.boundary.search.url=/boundary-service/boundary/_search +egov.boundary.hierarchy=HCM-Moz-Hierarchy diff --git a/health-services/household/src/main/resources/db/Dockerfile b/health-services/household/src/main/resources/db/Dockerfile index 60fc07ce69f..e7da01d7f0b 100644 --- a/health-services/household/src/main/resources/db/Dockerfile +++ b/health-services/household/src/main/resources/db/Dockerfile @@ -1,4 +1,4 @@ -FROM egovio/flyway:4.1.2 +FROM egovio/flyway:10.7.1 COPY ./migration/main /flyway/sql @@ -6,4 +6,4 @@ COPY migrate.sh /usr/bin/migrate.sh RUN chmod +x /usr/bin/migrate.sh -CMD ["/usr/bin/migrate.sh"] \ No newline at end of file +ENTRYPOINT ["/usr/bin/migrate.sh"] \ No newline at end of file diff --git a/health-services/household/src/main/resources/db/migrate.sh b/health-services/household/src/main/resources/db/migrate.sh index 43960b25cdb..f9d6617822c 100644 --- a/health-services/household/src/main/resources/db/migrate.sh +++ b/health-services/household/src/main/resources/db/migrate.sh @@ -1,3 +1,3 @@ #!/bin/sh -flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS -baselineOnMigrate=true -outOfOrder=true -ignoreMissingMigrations=true migrate \ No newline at end of file +flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS -baselineOnMigrate=true -outOfOrder=true migrate diff --git a/health-services/household/src/main/resources/db/migration/main/V20230628171400__add_client_audit_details_in_household_ddl.sql b/health-services/household/src/main/resources/db/migration/main/V20230628171400__add_client_audit_details_in_household_ddl.sql new file mode 100644 index 00000000000..f20e702d56c --- /dev/null +++ b/health-services/household/src/main/resources/db/migration/main/V20230628171400__add_client_audit_details_in_household_ddl.sql @@ -0,0 +1,5 @@ +ALTER TABLE HOUSEHOLD ADD COLUMN clientCreatedTime bigint; +ALTER TABLE HOUSEHOLD ADD COLUMN clientLastModifiedTime bigint; + +ALTER TABLE HOUSEHOLD_MEMBER ADD COLUMN clientCreatedTime bigint; +ALTER TABLE HOUSEHOLD_MEMBER ADD COLUMN clientLastModifiedTime bigint; \ No newline at end of file diff --git a/health-services/household/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_household_ddl.sql b/health-services/household/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_household_ddl.sql new file mode 100644 index 00000000000..f2fe18e299f --- /dev/null +++ b/health-services/household/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_household_ddl.sql @@ -0,0 +1,5 @@ +ALTER TABLE HOUSEHOLD ADD COLUMN IF NOT EXISTS clientCreatedBy character varying(64); +ALTER TABLE HOUSEHOLD ADD COLUMN IF NOT EXISTS clientLastModifiedBy character varying(64); + +ALTER TABLE HOUSEHOLD_MEMBER ADD COLUMN IF NOT EXISTS clientCreatedBy character varying(64); +ALTER TABLE HOUSEHOLD_MEMBER ADD COLUMN IF NOT EXISTS clientLastModifiedBy character varying(64); \ No newline at end of file diff --git a/health-services/household/src/main/resources/db/migration/main/V20231103055800__household_member_clientrefid_ddl.sql b/health-services/household/src/main/resources/db/migration/main/V20231103055800__household_member_clientrefid_ddl.sql new file mode 100644 index 00000000000..ff837451404 --- /dev/null +++ b/health-services/household/src/main/resources/db/migration/main/V20231103055800__household_member_clientrefid_ddl.sql @@ -0,0 +1,2 @@ +ALTER TABLE HOUSEHOLD_MEMBER ADD COLUMN IF NOT EXISTS clientreferenceid character varying(256); +ALTER TABLE HOUSEHOLD_MEMBER ALTER COLUMN clientreferenceid SET NOT NULL; diff --git a/health-services/household/src/main/resources/db/migration/main/V20240305114132__household_search_index_ddl.sql b/health-services/household/src/main/resources/db/migration/main/V20240305114132__household_search_index_ddl.sql new file mode 100644 index 00000000000..5228a08ba4d --- /dev/null +++ b/health-services/household/src/main/resources/db/migration/main/V20240305114132__household_search_index_ddl.sql @@ -0,0 +1 @@ +CREATE INDEX IF NOT EXISTS idx_household_tenantId_isDeleted_addressId ON household(tenantId, isDeleted, addressId); \ No newline at end of file diff --git a/health-services/household/src/main/resources/db/migration/main/V20240305114225__household_member_search_index_ddl.sql b/health-services/household/src/main/resources/db/migration/main/V20240305114225__household_member_search_index_ddl.sql new file mode 100644 index 00000000000..9e7995c915f --- /dev/null +++ b/health-services/household/src/main/resources/db/migration/main/V20240305114225__household_member_search_index_ddl.sql @@ -0,0 +1 @@ +CREATE INDEX IF NOT EXISTS idx_household_member_id ON household_member(id); \ No newline at end of file diff --git a/health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberSearchRequestTestBuilder.java b/health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberSearchRequestTestBuilder.java new file mode 100644 index 00000000000..868e354278b --- /dev/null +++ b/health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberSearchRequestTestBuilder.java @@ -0,0 +1,20 @@ +package org.egov.household.helper; + +import org.egov.common.models.household.HouseholdMemberSearchRequest; + +public class HouseholdMemberSearchRequestTestBuilder { + private HouseholdMemberSearchRequest.HouseholdMemberSearchRequestBuilder builder; + + public HouseholdMemberSearchRequestTestBuilder() { + this.builder = HouseholdMemberSearchRequest.builder(); + } + public static HouseholdMemberSearchRequestTestBuilder builder() { + return new HouseholdMemberSearchRequestTestBuilder(); + } + + public HouseholdMemberSearchRequest build() { + return this.builder.build(); + } + + +} diff --git a/health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberTestBuilder.java b/health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberTestBuilder.java index 8a4cfb9d1a8..140f6b3f84f 100644 --- a/health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberTestBuilder.java +++ b/health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberTestBuilder.java @@ -1,16 +1,17 @@ package org.egov.household.helper; import org.egov.common.helper.AuditDetailsTestBuilder; -import org.egov.common.models.household.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; +import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdMember; public class HouseholdMemberTestBuilder { - private HouseholdMember.HouseholdMemberBuilder builder; + private HouseholdMember.HouseholdMemberBuilder builder; public HouseholdMemberTestBuilder() { - this.builder = HouseholdMember.builder(); + this.builder = (HouseholdMember.HouseholdMemberBuilder) HouseholdMember.builder(); } public static HouseholdMemberTestBuilder builder() { @@ -22,7 +23,9 @@ public HouseholdMember build() { } public HouseholdMemberTestBuilder withHouseholdIdAndIndividualId(){ - this.builder.id("some-id").additionalFields(AdditionalFields.builder().build()) + this.builder.id("some-id") + .clientReferenceId("some-client-reference-id") + .additionalFields(AdditionalFields.builder().build()) .rowVersion(1) .isHeadOfHousehold(false) .individualId("some-individual-id") diff --git a/health-services/household/src/test/java/org/egov/household/helper/HouseholdSearchTestBuilder.java b/health-services/household/src/test/java/org/egov/household/helper/HouseholdSearchTestBuilder.java new file mode 100644 index 00000000000..aee59e664e5 --- /dev/null +++ b/health-services/household/src/test/java/org/egov/household/helper/HouseholdSearchTestBuilder.java @@ -0,0 +1,39 @@ +package org.egov.household.helper; + +import java.util.Collections; + +import org.egov.common.models.household.HouseholdSearch; + + +public class HouseholdSearchTestBuilder { + + private HouseholdSearch.HouseholdSearchBuilder builder; + + public HouseholdSearchTestBuilder() { + this.builder = (HouseholdSearch.HouseholdSearchBuilder) HouseholdSearch.builder(); + } + + public static HouseholdSearchTestBuilder builder() { + return new HouseholdSearchTestBuilder(); + } + + public HouseholdSearch build() { + return this.builder.build(); + } + + public HouseholdSearchTestBuilder withHouseholdSearch(){ + this.builder.id(Collections.singletonList("some-id")) + .clientReferenceId(Collections.singletonList("some-id")); + return this; + } + + public HouseholdSearchTestBuilder withId(String id) { + this.builder.id(Collections.singletonList(id)); + return this; + } + + public HouseholdSearchTestBuilder withClientReferenceId(String clientReferenceId) { + this.builder.clientReferenceId(Collections.singletonList(clientReferenceId)); + return this; + } +} diff --git a/health-services/household/src/test/java/org/egov/household/helper/HouseholdTestBuilder.java b/health-services/household/src/test/java/org/egov/household/helper/HouseholdTestBuilder.java index e891b3e51bd..c80173a9af9 100644 --- a/health-services/household/src/test/java/org/egov/household/helper/HouseholdTestBuilder.java +++ b/health-services/household/src/test/java/org/egov/household/helper/HouseholdTestBuilder.java @@ -1,17 +1,17 @@ package org.egov.household.helper; import org.egov.common.helper.AuditDetailsTestBuilder; -import org.egov.common.models.household.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.household.Address; import org.egov.common.models.household.Household; public class HouseholdTestBuilder { - private Household.HouseholdBuilder builder; + private Household.HouseholdBuilder builder; public HouseholdTestBuilder() { - this.builder = Household.builder(); + this.builder = (Household.HouseholdBuilder) Household.builder(); } public static HouseholdTestBuilder builder() { diff --git a/health-services/household/src/test/java/org/egov/household/service/HouseholdFindTest.java b/health-services/household/src/test/java/org/egov/household/service/HouseholdFindTest.java index 59071f2e372..91a0f2b2424 100644 --- a/health-services/household/src/test/java/org/egov/household/service/HouseholdFindTest.java +++ b/health-services/household/src/test/java/org/egov/household/service/HouseholdFindTest.java @@ -1,10 +1,13 @@ package org.egov.household.service; import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.ds.Tuple; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.household.Household; import org.egov.household.repository.HouseholdRepository; -import org.egov.household.web.models.HouseholdSearch; -import org.egov.household.web.models.HouseholdSearchRequest; +import org.egov.common.models.household.HouseholdSearch; +import org.egov.common.models.household.HouseholdSearchRequest; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -40,7 +43,7 @@ void shouldOnlySearchByIdIfOnlyIdIsPresent() throws QueryBuilderException { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .household(HouseholdSearch.builder().id(Collections.singletonList("some-id")).build()).build(); when(householdRepository.findById(anyList(), eq("id"), anyBoolean())) - .thenReturn(Collections.emptyList()); + .thenReturn(SearchResponse.builder().build()); householdService.search(householdSearchRequest.getHousehold(), 10, 0, "default", null, false); @@ -56,7 +59,7 @@ void shouldOnlySearchByClientReferenceIdIfOnlyClientReferenceIdIsPresent() throw .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .household(HouseholdSearch.builder().clientReferenceId(Collections.singletonList("some-id")).build()).build(); when(householdRepository.findById(anyList(), eq("clientReferenceId"), anyBoolean())) - .thenReturn(Collections.emptyList()); + .thenReturn(SearchResponse.builder().build()); householdService.search(householdSearchRequest.getHousehold(), 10, 0, "default", null, false); @@ -67,13 +70,13 @@ void shouldOnlySearchByClientReferenceIdIfOnlyClientReferenceIdIsPresent() throw @Test @DisplayName("should not call findById if more search parameters are available") - void shouldNotCallFindByIfIfMoreParametersAreAvailable() throws QueryBuilderException { + void shouldNotCallFindByIdIfMoreParametersAreAvailable() throws QueryBuilderException { HouseholdSearchRequest householdSearchRequest = HouseholdSearchRequest.builder() .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .household(HouseholdSearch.builder().id(Collections.singletonList("someid")) .clientReferenceId(Collections.singletonList("some-id")).build()).build(); when(householdRepository.find(any(HouseholdSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(SearchResponse.builder().build()); householdService.search(householdSearchRequest.getHousehold(), 10, 0, "default", 0L, false); @@ -90,7 +93,7 @@ void shouldCallFindIfMoreParametersAreAvailable() throws QueryBuilderException { .household(HouseholdSearch.builder().id(Collections.singletonList("someid")) .clientReferenceId(Collections.singletonList("some-id")).build()).build(); when(householdRepository.find(any(HouseholdSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(SearchResponse.builder().build()); householdService.search(householdSearchRequest.getHousehold(), 10, 0, "default", 0L, false); diff --git a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberCreateEnrichmentTest.java b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberCreateEnrichmentTest.java index 5325b641339..5947df9657a 100644 --- a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberCreateEnrichmentTest.java +++ b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberCreateEnrichmentTest.java @@ -1,5 +1,7 @@ package org.egov.household.service; +import org.egov.common.ds.Tuple; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdMemberBulkRequest; import org.egov.household.helper.HouseholdMemberBulkRequestTestBuilder; @@ -44,10 +46,10 @@ private void mockHouseholdFindIds() { any(List.class), any(String.class), any(Boolean.class) - )).thenReturn( - Collections.singletonList( - Household.builder().id("some-household-id").clientReferenceId("some-client-ref-id").build()) - ); + )).thenReturn(SearchResponse.builder() + .response(Collections.singletonList( + Household.builder().id("some-household-id").clientReferenceId("some-client-ref-id").build())) + .build()); } @Test diff --git a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberFindTest.java b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberFindTest.java index 13875c1bdd8..614189e57a1 100644 --- a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberFindTest.java +++ b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberFindTest.java @@ -2,9 +2,11 @@ import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.household.HouseholdMember; import org.egov.household.repository.HouseholdMemberRepository; -import org.egov.household.web.models.HouseholdMemberSearch; -import org.egov.household.web.models.HouseholdMemberSearchRequest; +import org.egov.common.models.household.HouseholdMemberSearch; +import org.egov.common.models.household.HouseholdMemberSearchRequest; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -41,7 +43,7 @@ void shouldOnlySearchByIdIfOnlyIdIsPresent() { .householdMemberSearch(HouseholdMemberSearch.builder() .id(Collections.singletonList("some-id")).build()).build(); when(householdMemberRepository.findById(anyList(), eq("id"), anyBoolean())) - .thenReturn(Collections.emptyList()); + .thenReturn(SearchResponse.builder().build()); householdMemberService.search(householdSearchRequest.getHouseholdMemberSearch(), 10, 0, "default", null, false); @@ -57,9 +59,9 @@ void shouldNotCallFindByIfIfMoreParametersAreAvailable() throws QueryBuilderExce HouseholdMemberSearchRequest householdMemberSearchRequest = HouseholdMemberSearchRequest.builder() .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .householdMemberSearch(HouseholdMemberSearch.builder() - .id(Collections.singletonList("some-id")).householdId("household-id").build()).build(); + .id(Collections.singletonList("some-id")).householdId(Collections.singletonList("household-id")).build()).build(); when(householdMemberRepository.find(any(HouseholdMemberSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(SearchResponse.builder().build()); householdMemberService.search(householdMemberSearchRequest.getHouseholdMemberSearch(), 10, 0, "", 0L, false); @@ -75,9 +77,9 @@ void shouldCallFindIfMoreParametersAreAvailable() throws QueryBuilderException { HouseholdMemberSearchRequest householdMemberSearchRequest = HouseholdMemberSearchRequest.builder() .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .householdMemberSearch(HouseholdMemberSearch.builder() - .id(Collections.singletonList("some-id")).householdId("household-id").build()).build(); + .id(Collections.singletonList("some-id")).householdId(Collections.singletonList("household-id")).build()).build(); when(householdMemberRepository.find(any(HouseholdMemberSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(SearchResponse.builder().build()); householdMemberService.search(householdMemberSearchRequest.getHouseholdMemberSearch(), 10, 0, "default", 0L, false); diff --git a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateEnrichmentTest.java b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateEnrichmentTest.java index f848169ab6d..7c25e9e465f 100644 --- a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateEnrichmentTest.java +++ b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateEnrichmentTest.java @@ -1,5 +1,7 @@ package org.egov.household.service; +import org.egov.common.ds.Tuple; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdMember; import org.egov.common.models.household.HouseholdMemberBulkRequest; @@ -43,9 +45,10 @@ private void mockHouseholdFindIds() { any(List.class), any(String.class), any(Boolean.class) - )).thenReturn( - Collections.singletonList( - Household.builder().id("some-household-id").clientReferenceId("some-client-ref-id").build()) + )).thenReturn(SearchResponse.builder() + .response(Collections.singletonList( + Household.builder().id("some-household-id").clientReferenceId("some-client-ref-id").build())) + .build() ); } @@ -55,8 +58,8 @@ private void mockFindById() { any(String.class), any(Boolean.class) )).thenReturn( - Collections.singletonList( - HouseholdMember.builder().id("some-id").build()) + SearchResponse.builder().response(Collections.singletonList( + HouseholdMember.builder().id("some-id").build())).build() ); } diff --git a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateTest.java b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateTest.java index 4c5bfc4ecb4..486bc9cbdb8 100644 --- a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateTest.java +++ b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateTest.java @@ -1,6 +1,8 @@ package org.egov.household.service; +import org.egov.common.ds.Tuple; import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdMember; import org.egov.common.models.household.HouseholdMemberBulkRequest; @@ -112,9 +114,10 @@ private void mockHouseholdFindIds() { any(List.class), any(String.class), any(Boolean.class) - )).thenReturn( - Collections.singletonList( - Household.builder().id("some-household-id").clientReferenceId("some-client-ref-id").build()) + )).thenReturn(SearchResponse.builder() + .response(Collections.singletonList( + Household.builder().id("some-household-id").clientReferenceId("some-client-ref-id").build())) + .build() ); } @@ -132,11 +135,11 @@ private void mockServiceRequestClientWithIndividual() throws Exception { } private void mockIndividualMapping(){ - when(householdMemberRepository.findIndividual(anyString())).thenReturn(Collections.singletonList( + when(householdMemberRepository.findIndividual(anyString())).thenReturn(SearchResponse.builder().response(Collections.singletonList( HouseholdMember.builder() .individualId("some-other-individual") .build() - )); + )).build()); } @Test diff --git a/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdApiControllerTest.java b/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdApiControllerTest.java index e88b5159631..baf3fe15cfe 100644 --- a/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdApiControllerTest.java +++ b/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdApiControllerTest.java @@ -1,15 +1,19 @@ package org.egov.household.web.controllers; import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.common.ds.Tuple; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.household.Household; import org.egov.common.producer.Producer; import org.egov.household.TestConfiguration; import org.egov.household.config.HouseholdConfiguration; import org.egov.household.config.HouseholdMemberConfiguration; +import org.egov.household.helper.HouseholdSearchTestBuilder; import org.egov.household.service.HouseholdMemberService; import org.egov.household.service.HouseholdService; -import org.egov.household.web.models.HouseholdSearch; -import org.egov.household.web.models.HouseholdSearchRequest; +import org.egov.common.models.household.HouseholdSearch; +import org.egov.common.models.household.HouseholdSearchRequest; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -20,6 +24,7 @@ import org.springframework.test.web.servlet.MockMvc; import java.util.Collections; +import java.util.List; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -58,14 +63,15 @@ class HouseholdApiControllerTest { @MockBean private HouseholdMemberConfiguration householdMemberConfiguration; + @Test @DisplayName("should household search request pass if all the required query parameters are present") void shouldSearchRequestPassIfQueryParamsArePresent() throws Exception { HouseholdSearchRequest householdSearchRequest = HouseholdSearchRequest.builder() .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) - .household(HouseholdSearch.builder().build()).build(); + .household(HouseholdSearchTestBuilder.builder().withHouseholdSearch().build()).build(); when(householdService.search(any(HouseholdSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), any(), any())).thenReturn(SearchResponse.builder().build()); mockMvc.perform(post("/v1/_search?limit=10&offset=0&tenantId=default").contentType(MediaType .APPLICATION_JSON).content(objectMapper.writeValueAsString(householdSearchRequest))) @@ -79,10 +85,10 @@ void shouldSearchRequestPassIfQueryParamsAreMissing() throws Exception { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .household(HouseholdSearch.builder().build()).build(); when(householdService.search(any(HouseholdSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(SearchResponse.builder().build()); mockMvc.perform(post("/v1/_search?limit=10&offset=0").contentType(MediaType .APPLICATION_JSON).content(objectMapper.writeValueAsString(householdSearchRequest))) .andExpect(status().isBadRequest()); } -} +} \ No newline at end of file diff --git a/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdMemberApiControllerTest.java b/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdMemberApiControllerTest.java index 8125e1b1a82..f6bb7609e38 100644 --- a/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdMemberApiControllerTest.java +++ b/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdMemberApiControllerTest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.household.HouseholdMember; import org.egov.common.models.household.HouseholdMemberRequest; import org.egov.common.producer.Producer; import org.egov.household.TestConfiguration; @@ -10,8 +12,8 @@ import org.egov.household.helper.HouseholdMemberRequestTestBuilder; import org.egov.household.service.HouseholdMemberService; import org.egov.household.service.HouseholdService; -import org.egov.household.web.models.HouseholdMemberSearch; -import org.egov.household.web.models.HouseholdMemberSearchRequest; +import org.egov.common.models.household.HouseholdMemberSearch; +import org.egov.common.models.household.HouseholdMemberSearchRequest; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -76,14 +78,15 @@ void householdMemberV1CreatePostSuccess() throws Exception { } - @Test +// @Test + //FIXME need to remove the this test cases and it is to be re-written. @DisplayName("should household member search request pass if all the required query parameters are present") void shouldSearchRequestPassIfQueryParamsArePresent() throws Exception { HouseholdMemberSearchRequest householdMemberSearchRequest = HouseholdMemberSearchRequest.builder() .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .householdMemberSearch(HouseholdMemberSearch.builder().build()).build(); when(householdMemberService.search(any(HouseholdMemberSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), any(), anyBoolean())).thenReturn(SearchResponse.builder().build()); mockMvc.perform(post("/member/v1/_search?limit=10&offset=0&tenantId=default").contentType(MediaType .APPLICATION_JSON).content(objectMapper.writeValueAsString(householdMemberSearchRequest))) @@ -97,7 +100,7 @@ void shouldSearchRequestPassIfQueryParamsAreMissing() throws Exception { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .householdMemberSearch(HouseholdMemberSearch.builder().build()).build(); when(householdMemberService.search(any(HouseholdMemberSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(SearchResponse.builder().build()); mockMvc.perform(post("/member/v1/_search?limit=10&offset=0").contentType(MediaType .APPLICATION_JSON).content(objectMapper.writeValueAsString(householdMemberSearchRequest))) diff --git a/health-services/individual/CHANGELOG.md b/health-services/individual/CHANGELOG.md index a27826b5875..2ac982c765d 100644 --- a/health-services/individual/CHANGELOG.md +++ b/health-services/individual/CHANGELOG.md @@ -1,5 +1,35 @@ 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 + +- Integrated Core 2.9LTS +- Client reference ID validation added +- Upgraded to health models 1.0.20 and health common 1.0.16 +- Boundary v2 Integration +- MDMS v2 integration +- 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 + +## 1.1.4 - 2024-05-10 +- Integrated Boundary v2 functionality +- +## 1.1.3 +- Added ability to search by user UUID for individual search. + +## 1.1.2 +- upgraded version from beta + +## 1.1.2-beta + +- Added proximity based search support + + ## 1.0.0 -- Base version \ No newline at end of file +- Base version + diff --git a/health-services/individual/README.md b/health-services/individual/README.md index c548ad3af6d..127a16ccdfa 100644 --- a/health-services/individual/README.md +++ b/health-services/individual/README.md @@ -53,3 +53,11 @@ g) POST `/individual/v1/_search` - Search Individual, This API is internally cal ## Pre commit script [commit-msg](https://gist.github.com/jayantp-egov/14f55deb344f1648503c6be7e580fa12) + +## Updates +- Individual Search + - `individualId`, and `mobileNumber` now accepts a list of entities instead of single entity to search individual +## Usage +- Start the service +- Access the API endpoints for searching `individual` +- Pass list parameters for the search fields mentioned in updates \ No newline at end of file diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index 7574e2cc721..84ca10da8d3 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -5,16 +5,17 @@ individual jar individual - 1.0.0 + 1.1.6 - 1.8 + 17 ${java.version} ${java.version} + 1.18.22 org.springframework.boot spring-boot-starter-parent - 2.2.6.RELEASE + 3.2.2 src/main/java @@ -30,6 +31,14 @@ + + org.apache.maven.plugins + maven-surefire-plugin + 3.1.2 + + --add-opens java.base/java.util=ALL-UNNAMED + + @@ -44,29 +53,40 @@ org.egov.common health-services-common - 1.0.11-SNAPSHOT + 1.0.18-SNAPSHOT org.egov.common health-services-models - 1.0.3-SNAPSHOT + 1.0.20-SNAPSHOT compile org.flywaydb flyway-core + 9.22.3 org.postgresql postgresql - 42.2.2.jre7 + 42.7.1 + + + org.egov.services + tracer + 2.9.0-SNAPSHOT org.springframework.boot spring-boot-starter-test test - + + junit + junit + 4.13.2 + test + io.swagger swagger-core @@ -76,12 +96,13 @@ org.projectlombok lombok + ${lombok.version} true org.egov enc-client - 2.0.4-SNAPSHOT + 2.9.0 org.egov.services @@ -94,11 +115,6 @@ com.fasterxml.jackson.datatype jackson-datatype-jsr310 - - - javax.validation - validation-api - diff --git a/health-services/individual/src/main/java/org/egov/individual/Constants.java b/health-services/individual/src/main/java/org/egov/individual/Constants.java index 8df6088b70b..9db46cf85e9 100644 --- a/health-services/individual/src/main/java/org/egov/individual/Constants.java +++ b/health-services/individual/src/main/java/org/egov/individual/Constants.java @@ -17,4 +17,5 @@ public interface Constants { String INDIVIDUAL_MODULE_CODE = "rainmaker-masters"; String INDIVIDUAL_LOCALIZATION_CODES_JSONPATH = "$.messages.*.code"; String INDIVIDUAL_LOCALIZATION_MSGS_JSONPATH = "$.messages.*.message"; + String ORG_ADMIN_ROLE_CODE = "ORG_ADMIN"; } diff --git a/health-services/individual/src/main/java/org/egov/individual/config/IndividualProperties.java b/health-services/individual/src/main/java/org/egov/individual/config/IndividualProperties.java index d481b47d5c8..34d4dd59f16 100644 --- a/health-services/individual/src/main/java/org/egov/individual/config/IndividualProperties.java +++ b/health-services/individual/src/main/java/org/egov/individual/config/IndividualProperties.java @@ -7,6 +7,8 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import java.util.List; + @Data @AllArgsConstructor @NoArgsConstructor @@ -63,6 +65,9 @@ public class IndividualProperties { @Value("${kafka.topics.notification.sms}") private String smsNotifTopic; + @Value("${notification.sms.disabled.roles}") + private List smsDisabledRoles; + //Localization @Value("${egov.localization.host}") private String localizationHost; @@ -75,4 +80,10 @@ public class IndividualProperties { @Value("${egov.localization.statelevel}") private Boolean isLocalizationStateLevel; + + @Value("${egov.boundary.host}") + private String boundaryServiceHost; + + @Value("${egov.boundary.search.url}") + private String boundarySearchUrl; } diff --git a/health-services/individual/src/main/java/org/egov/individual/config/MainConfiguration.java b/health-services/individual/src/main/java/org/egov/individual/config/MainConfiguration.java index 788dbdc2af5..4256549fa4b 100644 --- a/health-services/individual/src/main/java/org/egov/individual/config/MainConfiguration.java +++ b/health-services/individual/src/main/java/org/egov/individual/config/MainConfiguration.java @@ -24,7 +24,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.util.TimeZone; @Import({TracerConfiguration.class}) diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index e34e5740623..e08aeef5d17 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -1,43 +1,50 @@ package org.egov.individual.repository; +import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.data.query.builder.GenericQueryBuilder; import org.egov.common.data.query.builder.QueryFieldChecker; import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.individual.Address; import org.egov.common.models.individual.Identifier; import org.egov.common.models.individual.Individual; +import org.egov.common.models.individual.IndividualSearch; import org.egov.common.models.individual.Skill; import org.egov.common.producer.Producer; import org.egov.individual.repository.rowmapper.AddressRowMapper; import org.egov.individual.repository.rowmapper.IdentifierRowMapper; import org.egov.individual.repository.rowmapper.IndividualRowMapper; import org.egov.individual.repository.rowmapper.SkillRowMapper; -import org.egov.individual.web.models.IndividualSearch; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; -import java.lang.reflect.Method; -import java.math.BigDecimal; -import java.time.Instant; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - +import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; import static org.egov.common.utils.CommonUtils.getIdMethod; @Repository @Slf4j public class IndividualRepository extends GenericRepository { + private final String cteQuery = "WITH cte_search_criteria_waypoint(s_latitude, s_longitude) AS (VALUES(:s_latitude, :s_longitude))"; + private final String calculateDistanceFromTwoWaypointsFormulaQuery = "( 6371.4 * acos ( LEAST ( GREATEST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), -1), 1) ) ) AS distance "; + protected IndividualRepository(@Qualifier("individualProducer") Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, RedisTemplate redisTemplate, @@ -47,44 +54,57 @@ protected IndividualRepository(@Qualifier("individualProducer") Producer produc selectQueryBuilder, individualRowMapper, Optional.of("individual")); } - public List findById(List ids, String idColumn, Boolean includeDeleted) { - List objFound; - objFound = findInCache(ids).stream() - .filter(individual -> individual.getIsDeleted().equals(includeDeleted)) - .collect(Collectors.toList()); - if (!objFound.isEmpty()) { - Method idMethod = getIdMethod(objFound, idColumn); - ids.removeAll(objFound.stream() - .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) - .collect(Collectors.toList())); - if (ids.isEmpty()) { - return objFound; + public SearchResponse findById(List ids, String idColumn, Boolean includeDeleted) { + List objFound = new ArrayList<>(); + try { + objFound = findInCache(ids); + if (!includeDeleted) { + objFound = objFound.stream() + .filter(entity -> entity.getIsDeleted().equals(false)) + .collect(Collectors.toList()); } + if (!objFound.isEmpty()) { + Method idMethod = getIdMethod(objFound, idColumn); + ids.removeAll(objFound.stream() + .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) + .collect(Collectors.toList())); + if (ids.isEmpty()) { + return SearchResponse.builder().totalCount(Long.valueOf(objFound.size())).response(objFound).build(); + } + } + }catch (Exception e){ + log.info("Error occurred while reading from cache", ExceptionUtils.getStackTrace(e)); } String individualQuery = String.format(getQuery("SELECT * FROM individual WHERE %s IN (:ids)", includeDeleted), idColumn); Map paramMap = new HashMap<>(); paramMap.put("ids", ids); + Long totalCount = constructTotalCountCTEAndReturnResult(individualQuery, paramMap, this.namedParameterJdbcTemplate); List individuals = this.namedParameterJdbcTemplate .query(individualQuery, paramMap, this.rowMapper); enrichIndividuals(individuals, includeDeleted); objFound.addAll(individuals); putInCache(objFound); - return objFound; + return SearchResponse.builder().totalCount(totalCount).response(objFound).build(); } - public List find(IndividualSearch searchObject, Integer limit, Integer offset, - String tenantId, Long lastChangedSince, Boolean includeDeleted) { + public SearchResponse find(IndividualSearch searchObject, Integer limit, Integer offset, + String tenantId, Long lastChangedSince, Boolean includeDeleted) { Map paramsMap = new HashMap<>(); String query = getQueryForIndividual(searchObject, limit, offset, tenantId, lastChangedSince, includeDeleted, paramsMap); + if (isProximityBasedSearch(searchObject)) { + return findByRadius(query, searchObject, includeDeleted, paramsMap); + } if (searchObject.getIdentifier() == null) { + String queryWithoutLimit = query.replace("ORDER BY id ASC LIMIT :limit OFFSET :offset", ""); + Long totalCount = constructTotalCountCTEAndReturnResult(queryWithoutLimit, paramsMap, this.namedParameterJdbcTemplate); List individuals = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); if (!individuals.isEmpty()) { enrichIndividuals(individuals, includeDeleted); } - return individuals; + return SearchResponse.builder().totalCount(totalCount).response(individuals).build(); } else { Map identifierParamMap = new HashMap<>(); String identifierQuery = getIdentifierQuery(searchObject.getIdentifier(), identifierParamMap); @@ -107,12 +127,85 @@ public List find(IndividualSearch searchObject, Integer limit, Integ enrichSkills(includeDeleted, individual, indServerGenIdParamMap); }); } - return individuals; + return SearchResponse.builder().response(individuals).build(); } - return Collections.emptyList(); + return SearchResponse.builder().build(); } } + /** + * @param query + * @param searchObject + * @param includeDeleted + * @param paramsMap + * @return Fetch all the household which falls under the radius provided using longitude and latitude provided. + */ + public SearchResponse findByRadius(String query, IndividualSearch searchObject, Boolean includeDeleted, Map paramsMap) { + query = query.replace("LIMIT :limit OFFSET :offset", ""); + paramsMap.put("s_latitude", searchObject.getLatitude()); + paramsMap.put("s_longitude", searchObject.getLongitude()); + if (searchObject.getIdentifier() != null) { + Map identifierParamMap = new HashMap<>(); + String identifierQuery = getIdentifierQuery(searchObject.getIdentifier(), identifierParamMap); + identifierParamMap.put("isDeleted", includeDeleted); + List identifiers = this.namedParameterJdbcTemplate + .query(identifierQuery, identifierParamMap, new IdentifierRowMapper()); + if (CollectionUtils.isEmpty(identifiers)) { + query = query.replace(" tenantId=:tenantId ", " tenantId=:tenantId AND id=:individualId "); + paramsMap.put("individualId", identifiers.stream().findAny().get().getIndividualId()); + query = cteQuery + ", cte_individual AS (" + query + ")"; + query = query + "SELECT * FROM (SELECT cte_i.*, " + calculateDistanceFromTwoWaypointsFormulaQuery + +" FROM cte_individual cte_i LEFT JOIN public.individual_address ia ON ia.individualid = cte_i.id LEFT JOIN public.address a ON ia.addressid = a.id , cte_search_criteria_waypoint cte_scw) rt "; + if(searchObject.getSearchRadius() != null) { + query = query + " WHERE rt.distance < :distance "; + } + query = query + " ORDER BY distance ASC "; + paramsMap.put("distance", searchObject.getSearchRadius()); + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + query = query + "LIMIT :limit OFFSET :offset"; + List individuals = this.namedParameterJdbcTemplate.query(query, + paramsMap, this.rowMapper); + if (!individuals.isEmpty()) { + individuals.forEach(individual -> { + individual.setIdentifiers(identifiers); + List
addresses = getAddressForIndividual(individual.getId(), includeDeleted); + individual.setAddress(addresses); + Map indServerGenIdParamMap = new HashMap<>(); + indServerGenIdParamMap.put("individualId", individual.getId()); + indServerGenIdParamMap.put("isDeleted", includeDeleted); + enrichSkills(includeDeleted, individual, indServerGenIdParamMap); + }); + } + return SearchResponse.builder().totalCount(totalCount).response(individuals).build(); + } + } else { + query = cteQuery + ", cte_individual AS (" + query + ")"; + query = query + "SELECT * FROM (SELECT cte_i.*, "+ calculateDistanceFromTwoWaypointsFormulaQuery + +" FROM cte_individual cte_i LEFT JOIN public.individual_address ia ON ia.individualid = cte_i.id LEFT JOIN public.address a ON ia.addressid = a.id , cte_search_criteria_waypoint cte_scw) rt "; + if(searchObject.getSearchRadius() != null) { + query = query + " WHERE rt.distance < :distance "; + } + query = query + " ORDER BY distance ASC "; + paramsMap.put("distance", searchObject.getSearchRadius()); + + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + + query = query + "LIMIT :limit OFFSET :offset"; + List individuals = this.namedParameterJdbcTemplate.query(query, + paramsMap, this.rowMapper); + if (!individuals.isEmpty()) { + enrichIndividuals(individuals, includeDeleted); + } + return SearchResponse.builder().totalCount(totalCount).response(individuals).build(); + } + return SearchResponse.builder().build(); + } + + + private Boolean isProximityBasedSearch(IndividualSearch searchObject) { + return searchObject.getLatitude() != null && searchObject.getLongitude() != null && searchObject.getSearchRadius() != null; + } + private void enrichSkills(Boolean includeDeleted, Individual individual, Map indServerGenIdParamMap) { String individualSkillQuery = getQuery("SELECT * FROM individual_skill WHERE individualId =:individualId", includeDeleted); @@ -126,7 +219,7 @@ private String getQueryForIndividual(IndividualSearch searchObject, Integer limi Boolean includeDeleted, Map paramsMap) { String query = "SELECT * FROM individual"; List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); - query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); + query = GenericQueryBuilder.generateQuery(query, whereFields).toString().trim(); query += " AND tenantId=:tenantId "; if (query.contains(tableName + " AND")) { @@ -170,12 +263,44 @@ private String getQueryForIndividual(IndividualSearch searchObject, Integer limi if (lastChangedSince != null) { query = query + "AND lastModifiedTime>=:lastModifiedTime "; } - query = query + "ORDER BY id ASC LIMIT :limit OFFSET :offset"; + if (searchObject.getRoleCodes() != null && !searchObject.getRoleCodes().isEmpty()) { + query = query + "AND roles @> '["; + for (int i = 0; i < searchObject.getRoleCodes().size(); i++) { + query = query + "{\"code\": \"" + searchObject.getRoleCodes().get(i) + "\"}"; + if (i != searchObject.getRoleCodes().size() - 1) { + query = query + ","; + } + } + query = query + "]' "; + } + + if (searchObject.getUsername() != null) { + query = query + "AND username in (:username) "; + paramsMap.put("username", searchObject.getUsername()); + } + + if (searchObject.getUserId() != null) { + query = query + "AND userId in (:userId) "; + paramsMap.put("userId", searchObject.getUserId().stream() + .map(Object::toString) + .collect(Collectors.toList())); + } + + if (searchObject.getUserUuid() != null) { + query = query + "AND userUuid in (:userUuid) "; + paramsMap.put("userUuid", searchObject.getUserUuid()); + } + + query = query + "ORDER BY createdtime DESC LIMIT :limit OFFSET :offset"; + paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); paramsMap.put("lastModifiedTime", lastChangedSince); paramsMap.put("limit", limit); paramsMap.put("offset", offset); + + log.info("query-------------------------->"); + log.info(query); return query; } @@ -187,7 +312,15 @@ private String getIdentifierQuery(Identifier identifier, Map par } private List
getAddressForIndividual(String individualId, Boolean includeDeleted) { - String addressQuery = getQuery("SELECT a.*, ia.individualId, ia.createdBy, ia.lastModifiedBy, ia.createdTime, ia.lastModifiedTime, ia.isDeleted FROM address a, individual_address ia WHERE a.id = ia.addressId and ia.individualId =:individualId", includeDeleted, "ia"); + String addressQuery = getQuery("SELECT a.*, ia.individualId, ia.addressId, ia.createdBy, ia.lastModifiedBy, ia.createdTime, ia.lastModifiedTime, ia.isDeleted" + + " FROM (" + + " SELECT individualId, addressId, type, createdBy, lastModifiedBy, createdTime, lastModifiedTime, isDeleted, " + + " ROW_NUMBER() OVER (PARTITION BY individualId, type ORDER BY lastModifiedTime DESC) AS rn" + + " FROM individual_address" + + " WHERE individualId = :individualId" + + " ) AS ia" + + " JOIN address AS a ON ia.addressId = a.id" + + " WHERE ia.rn = 1 ", includeDeleted, "ia"); Map indServerGenIdParamMap = new HashMap<>(); indServerGenIdParamMap.put("individualId", individualId); indServerGenIdParamMap.put("isDeleted", includeDeleted); diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/AddressRowMapper.java b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/AddressRowMapper.java index e7b11405186..48396c74988 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/AddressRowMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/AddressRowMapper.java @@ -3,7 +3,7 @@ import digit.models.coremodels.AuditDetails; import org.egov.common.models.individual.Address; import org.egov.common.models.individual.AddressType; -import org.egov.common.models.individual.Boundary; +import org.egov.common.models.core.Boundary; import org.springframework.jdbc.core.RowMapper; import java.sql.ResultSet; diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java index 0d3bffdbd9d..be0f5387bd4 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java @@ -1,19 +1,22 @@ package org.egov.individual.repository.rowmapper; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.individual.AdditionalFields; +import digit.models.coremodels.user.enums.UserType; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.individual.BloodGroup; import org.egov.common.models.individual.Gender; import org.egov.common.models.individual.Individual; import org.egov.common.models.individual.Name; +import org.egov.common.models.individual.UserDetails; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import java.sql.ResultSet; -import java.sql.SQLException; - @Component public class IndividualRowMapper implements RowMapper { @@ -22,11 +25,24 @@ public class IndividualRowMapper implements RowMapper { @Override public Individual mapRow(ResultSet resultSet, int i) throws SQLException { try { + String tenantId = resultSet.getString("tenantId"); + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) + .build(); return Individual.builder().id(resultSet.getString("id")) .individualId(resultSet.getString("individualid")) .userId(resultSet.getString("userId")) .clientReferenceId(resultSet.getString("clientReferenceId")) - .tenantId(resultSet.getString("tenantId")) + .tenantId(tenantId) .name(Name.builder().givenName(resultSet.getString("givenName")) .familyName(resultSet.getString("familyName")) .otherNames(resultSet.getString("otherNames")).build()) @@ -43,16 +59,24 @@ public Individual mapRow(ResultSet resultSet, int i) throws SQLException { .photo(resultSet.getString("photo")) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet.getString("additionalDetails"), - AdditionalFields.class)) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) + AdditionalFields.class) + ) + .auditDetails(auditDetails) .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) .isSystemUser(resultSet.getBoolean("isSystemUser")) + .isSystemUserActive(resultSet.getBoolean("isSystemUserActive")) + .userDetails(UserDetails.builder() + .username(resultSet.getString("username")) + .password(resultSet.getString("password")) + .userType(UserType.fromValue(resultSet.getString("type"))) + .roles(resultSet.getString("roles") == null ? null : + objectMapper.readValue(resultSet.getString("roles"), + List.class)) + .tenantId(tenantId) + .build()) + .userUuid(resultSet.getString("userUuid")) + .clientAuditDetails(clientAuditDetails) .build(); } catch (JsonProcessingException e) { throw new RuntimeException(e); diff --git a/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java b/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java index ec40a40633c..7ea9daff08e 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java @@ -1,5 +1,14 @@ package org.egov.individual.service; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + import digit.models.coremodels.AuditDetails; import lombok.extern.slf4j.Slf4j; import org.egov.common.contract.request.RequestInfo; @@ -14,14 +23,6 @@ import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - import static org.egov.common.utils.CommonUtils.collectFromList; import static org.egov.common.utils.CommonUtils.enrichForCreate; import static org.egov.common.utils.CommonUtils.enrichForDelete; @@ -49,7 +50,7 @@ public EnrichmentService(IdGenService idGenService, this.properties = properties; } - public void create(List validIndividuals, IndividualBulkRequest request) throws Exception { + public void create(List validIndividuals, IndividualBulkRequest request) { log.info("starting the enrichment for create individuals"); log.info("extracting tenantId"); @@ -229,6 +230,7 @@ private static Individual enrichWithSystemGeneratedIdentifier(Individual individ log.info("enriching individual with system generated identifier"); List identifiers = new ArrayList<>(); identifiers.add(Identifier.builder() + .clientReferenceId(UUID.randomUUID().toString()) .identifierType(SYSTEM_GENERATED) .identifierId(individual.getId()) .build()); diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualEncryptionService.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualEncryptionService.java index 75d5c123c9d..ee7fe12030b 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualEncryptionService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualEncryptionService.java @@ -2,15 +2,16 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.models.Error; import org.egov.common.models.ErrorDetails; import org.egov.common.models.individual.Identifier; import org.egov.common.models.individual.Individual; import org.egov.common.models.individual.IndividualBulkRequest; +import org.egov.common.models.individual.IndividualSearch; import org.egov.individual.repository.IndividualRepository; import org.egov.individual.util.EncryptionDecryptionUtil; -import org.egov.individual.web.models.IndividualSearch; import org.egov.tracer.model.CustomException; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -109,9 +110,9 @@ private void validateAadhaarUniqueness (List individuals, Individual List individualsList = null; try { individualsList = individualRepository.find(individualSearch,null, - null,tenantId,null,false); + null,tenantId,null,false).getResponse(); } catch (Exception exception) { - log.error("database error occurred", exception); + log.error("database error occurred", ExceptionUtils.getStackTrace(exception)); throw new CustomException("DATABASE_ERROR", exception.getMessage()); } if (!CollectionUtils.isEmpty(individualsList)) { diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java index ae1b5500ffc..99ec43470fd 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java @@ -1,17 +1,18 @@ package org.egov.individual.service; +import java.util.Random; +import java.util.UUID; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.individual.Address; +import org.egov.common.models.individual.AddressType; import org.egov.common.models.individual.Individual; import org.egov.common.models.user.RoleRequest; import org.egov.common.models.user.UserRequest; import org.egov.common.models.user.UserType; import org.egov.individual.config.IndividualProperties; -import java.util.Collections; -import java.util.HashSet; -import java.util.Random; -import java.util.UUID; - @Slf4j public class IndividualMapper { @@ -20,21 +21,34 @@ public class IndividualMapper { private IndividualMapper() {} public static UserRequest toUserRequest(Individual individual, IndividualProperties properties) { - + Long id = individual.getUserId() != null ? Long.parseLong(individual.getUserId()) : null; + String addressLine1 = individual.getAddress() != null && !individual.getAddress().isEmpty() + ? individual.getAddress().stream().filter(address -> address.getType() + .equals(AddressType.CORRESPONDENCE)).findFirst() + .orElse(Address.builder().build()) + .getAddressLine1() : null; return UserRequest.builder() + .id(id) + .uuid(individual.getUserUuid()) .tenantId(individual.getTenantId()) - .userName(UUID.randomUUID().toString()) - .name(String.join(" ", individual.getName().getGivenName(), - individual.getName().getFamilyName())) + .name(individual.getName().getFamilyName() != null ? String.join(" ", individual.getName().getGivenName(), + individual.getName().getFamilyName()) : individual.getName().getGivenName()) + .correspondenceAddress(addressLine1) + .emailId(individual.getEmail()) .mobileNumber(generateDummyMobileNumber(individual.getMobileNumber())) .type(UserType.valueOf(properties.getUserServiceUserType())) .accountLocked(properties.isUserServiceAccountLocked()) - .active(true) - .roles(new HashSet<>(Collections.singletonList(RoleRequest.builder() - .code(properties.getUserServiceUserType()) - .tenantId(individual.getTenantId()) - .name(properties.getUserServiceUserType()) - .build()))) + .active(individual.getIsSystemUserActive()) + .userName(null != individual.getUserDetails().getUsername() ? individual.getUserDetails().getUsername() : UUID.randomUUID().toString()) + .password(null != individual.getUserDetails().getPassword() ? individual.getUserDetails().getPassword() : null) + .roles(individual.getUserDetails().getRoles().stream().map(role -> RoleRequest.builder() + .code(role.getCode()) + .name(role.getName()) + .tenantId(individual.getTenantId()) + .build()) + .collect(Collectors.toSet())) + .type(UserType.fromValue(individual.getUserDetails().getUserType() != null + ? individual.getUserDetails().getUserType().name() : null)) .build(); } diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java index b247e5e4e6f..c700e51d4e8 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java @@ -1,32 +1,66 @@ package org.egov.individual.service; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.ds.Tuple; +import org.egov.common.models.Error; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.Role; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.individual.Identifier; import org.egov.common.models.individual.Individual; import org.egov.common.models.individual.IndividualBulkRequest; import org.egov.common.models.individual.IndividualRequest; +import org.egov.common.models.individual.IndividualSearch; import org.egov.common.models.project.ApiOperation; import org.egov.common.models.user.UserRequest; import org.egov.common.utils.CommonUtils; import org.egov.common.validator.Validator; import org.egov.individual.config.IndividualProperties; import org.egov.individual.repository.IndividualRepository; -import org.egov.individual.validators.*; -import org.egov.individual.web.models.IndividualSearch; +import org.egov.individual.validators.AadharNumberValidator; +import org.egov.individual.validators.AadharNumberValidatorForCreate; +import org.egov.individual.validators.AddressTypeValidator; +import org.egov.individual.validators.IBoundaryValidator; +import org.egov.individual.validators.IExistentEntityValidator; +import org.egov.individual.validators.IsDeletedSubEntityValidator; +import org.egov.individual.validators.IsDeletedValidator; +import org.egov.individual.validators.MobileNumberValidator; +import org.egov.individual.validators.NonExistentEntityValidator; +import org.egov.individual.validators.NullIdValidator; +import org.egov.individual.validators.RowVersionValidator; +import org.egov.individual.validators.UniqueEntityValidator; +import org.egov.individual.validators.UniqueSubEntityValidator; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; -import java.util.*; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.*; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdList; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.individual.Constants.SET_INDIVIDUALS; import static org.egov.individual.Constants.VALIDATION_ERROR; @@ -50,6 +84,7 @@ public class IndividualService { private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(NullIdValidator.class) + || validator.getClass().equals(IBoundaryValidator.class) || validator.getClass().equals(IsDeletedValidator.class) || validator.getClass().equals(IsDeletedSubEntityValidator.class) || validator.getClass().equals(NonExistentEntityValidator.class) @@ -62,6 +97,8 @@ public class IndividualService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(AddressTypeValidator.class) + || validator.getClass().equals(IExistentEntityValidator.class) + || validator.getClass().equals(IBoundaryValidator.class) || validator.getClass().equals(UniqueSubEntityValidator.class) || validator.getClass().equals(MobileNumberValidator.class) || validator.getClass().equals(AadharNumberValidatorForCreate.class); @@ -91,7 +128,9 @@ public List create(IndividualRequest request) { IndividualBulkRequest bulkRequest = IndividualBulkRequest.builder().requestInfo(request.getRequestInfo()) .individuals(Collections.singletonList(request.getIndividual())).build(); List individuals = create(bulkRequest, false); - if(properties.getIsSMSEnabled()) + + // check if sms feature is enable for the environment role + if(properties.getIsSMSEnabled() && isSmsEnabledForRole(request)) notificationService.sendNotification(request, true); return individuals; } @@ -114,8 +153,8 @@ public List create(IndividualBulkRequest request, boolean isBulk) { individualRepository.save(encryptedIndividualList, properties.getSaveIndividualTopic()); } - } catch (Exception exception) { - log.error("error occurred", exception); + } catch (CustomException exception) { + log.error("error occurred", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validIndividuals, exception, SET_INDIVIDUALS); } @@ -136,7 +175,12 @@ private Tuple, Map> validate(List hashset = new HashSet<>(); + for (Map.Entry entry : errorDetailsMap.entrySet()) { + List errors = entry.getValue().getErrors(); + hashset.addAll(errors.stream().map(error -> error.getErrorCode()).collect(Collectors.toSet())); + } + throw new CustomException(String.join(":", hashset), errorDetailsMap.values().toString()); } List validIndividuals = request.getIndividuals().stream() .filter(notHavingErrors()).collect(Collectors.toList()); @@ -147,7 +191,9 @@ public List update(IndividualRequest request) { IndividualBulkRequest bulkRequest = IndividualBulkRequest.builder().requestInfo(request.getRequestInfo()) .individuals(Collections.singletonList(request.getIndividual())).build(); List individuals = update(bulkRequest, false); - if(properties.getIsSMSEnabled()) + + // check if sms feature is enable for the environment role + if(properties.getIsSMSEnabled() && isSmsEnabledForRole(request)) notificationService.sendNotification(request, false); return individuals; } @@ -164,19 +210,25 @@ public List update(IndividualBulkRequest request, boolean isBulk) { if (!validIndividuals.isEmpty()) { log.info("processing {} valid entities", validIndividuals.size()); enrichmentService.update(validIndividuals, request); - - // get masked identifiers - List maskedIdentifiers = filterMaskedIdentifiers(validIndividuals); - // remove masked identifiers because we cannot encrypt them again - List individualsToEncrypt = validIndividuals.stream().map(individual -> { - if (!maskedIdentifiers.isEmpty()) { - individual.getIdentifiers().removeAll(maskedIdentifiers - .stream().filter(identifier -> - identifier.getIndividualId().equals(individual.getId())) - .collect(Collectors.toList())); - } - return individual; - }).collect(Collectors.toList()); + boolean identifiersPresent = validIndividuals.stream() + .anyMatch(individual -> individual.getIdentifiers() != null + && !individual.getIdentifiers().isEmpty()); + + List individualsToEncrypt = validIndividuals; + if (identifiersPresent) { + // get masked identifiers + List maskedIdentifiers = filterMaskedIdentifiers(validIndividuals); + // remove masked identifiers because we cannot encrypt them again + individualsToEncrypt = validIndividuals.stream().map(individual -> { + if (!maskedIdentifiers.isEmpty()) { + individual.getIdentifiers().removeAll(maskedIdentifiers + .stream().filter(identifier -> + identifier.getIndividualId().equals(individual.getId())) + .collect(Collectors.toList())); + } + return individual; + }).collect(Collectors.toList()); + } // encrypt new data @@ -187,28 +239,35 @@ public List update(IndividualBulkRequest request, boolean isBulk) { Map idToObjMap = getIdToObjMap(encryptedIndividualList); // find existing individuals from db List existingIndividuals = individualRepository.findById(new ArrayList<>(idToObjMap.keySet()), - "id", false); - // extract existing identifiers (encrypted) from existing individuals - Map> existingIdentifiers = existingIndividuals.stream() - .map(Individual::getIdentifiers) - .filter(Objects::nonNull) - .flatMap(Collection::stream).collect(Collectors.groupingBy(Identifier::getIndividualId)); - // merge existing identifiers with new identifiers such that they all are encrypted alike - // this is because we cannot merge masked identifiers with new identifiers which are now encrypted - encryptedIndividualList.forEach(encryptedIndividual -> { - List newIdentifiers = encryptedIndividual.getIdentifiers(); - List identifierList = existingIdentifiers.get(encryptedIndividual.getId()); - if (identifierList != null) { - newIdentifiers.addAll(identifierList); - } - }); + "id", false).getResponse(); + + if (identifiersPresent) { + // extract existing identifiers (encrypted) from existing individuals + Map> existingIdentifiers = existingIndividuals.stream() + .map(Individual::getIdentifiers) + .filter(Objects::nonNull) + .flatMap(Collection::stream).collect(Collectors.groupingBy(Identifier::getIndividualId)); + // merge existing identifiers with new identifiers such that they all are encrypted alike + // this is because we cannot merge masked identifiers with new identifiers which are now encrypted + encryptedIndividualList.forEach(encryptedIndividual -> { + List newIdentifiers = encryptedIndividual.getIdentifiers(); + List newIdentifiersIds = getIdList(newIdentifiers); + List identifierList = existingIdentifiers.get(encryptedIndividual.getId()).stream() + .filter(identifier -> !newIdentifiersIds.contains(identifier.getId())) + .collect(Collectors.toList()); + + if (identifierList != null) { + newIdentifiers.addAll(identifierList); + } + }); + } // save individualRepository.save(encryptedIndividualList, properties.getUpdateIndividualTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); + log.error("error occurred", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validIndividuals, exception, SET_INDIVIDUALS); } @@ -227,13 +286,15 @@ private List filterMaskedIdentifiers(List validIndividua .collect(Collectors.toList()); } - public List search(IndividualSearch individualSearch, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted, - RequestInfo requestInfo) { + public SearchResponse search(IndividualSearch individualSearch, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted, + RequestInfo requestInfo) { + SearchResponse searchResponse = null; + String idFieldName = getIdFieldName(individualSearch); List encryptedIndividualList = null; if (isSearchByIdOnly(individualSearch, idFieldName)) { @@ -241,16 +302,22 @@ public List search(IndividualSearch individualSearch, .singletonList(individualSearch)), individualSearch); - encryptedIndividualList = individualRepository.findById(ids, idFieldName, includeDeleted) - .stream().filter(lastChangedSince(lastChangedSince)) + searchResponse = individualRepository.findById(ids, idFieldName, includeDeleted); + + encryptedIndividualList = searchResponse.getResponse().stream() + .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); //decrypt - return (!encryptedIndividualList.isEmpty()) + List decryptedIndividualList = (!encryptedIndividualList.isEmpty()) ? individualEncryptionService.decrypt(encryptedIndividualList, "IndividualDecrypt", requestInfo) : encryptedIndividualList; + + searchResponse.setResponse(decryptedIndividualList); + + return searchResponse; } //encrypt search criteria @@ -266,20 +333,24 @@ public List search(IndividualSearch individualSearch, .encrypt(individualSearch, "IndividualSearchEncrypt"); } try { - encryptedIndividualList = individualRepository.find(encryptedIndividualSearch, limit, offset, tenantId, - lastChangedSince, includeDeleted).stream() + searchResponse = individualRepository.find(encryptedIndividualSearch, limit, offset, tenantId, + lastChangedSince, includeDeleted); + encryptedIndividualList = searchResponse.getResponse().stream() .filter(havingBoundaryCode(individualSearch.getBoundaryCode(), individualSearch.getWardCode())) .collect(Collectors.toList()); } catch (Exception exception) { - log.error("database error occurred", exception); + log.error("database error occurred", ExceptionUtils.getStackTrace(exception)); throw new CustomException("DATABASE_ERROR", exception.getMessage()); } //decrypt - return (!encryptedIndividualList.isEmpty()) + List decryptedIndividualList = (!encryptedIndividualList.isEmpty()) ? individualEncryptionService.decrypt(encryptedIndividualList, "IndividualDecrypt", requestInfo) : encryptedIndividualList; + searchResponse.setResponse(decryptedIndividualList); + + return searchResponse; } private Predicate havingBoundaryCode(String boundaryCode, String wardCode) { @@ -318,7 +389,7 @@ public List delete(IndividualBulkRequest request, boolean isBulk) { properties.getDeleteIndividualTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); + log.error("error occurred", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validIndividuals, exception, SET_INDIVIDUALS); } @@ -345,12 +416,15 @@ private void integrateWithUserService(IndividualBulkRequest request, log.info("successfully updated user for {} individuals", encryptedIndividualList.size()); } else if (apiOperation.equals(ApiOperation.CREATE)) { - Long userId = userIntegrationService.createUser(encryptedIndividualList, - request.getRequestInfo()).map(UserRequest::getId).orElse(null); - encryptedIndividualList.stream().filter(Individual::getIsSystemUser) - .forEach(individual -> - individual.setUserId(userId != null ? - Long.toString(userId) : null)); + List userRequests = userIntegrationService.createUser(encryptedIndividualList, + request.getRequestInfo()); + for (int i = 0; i < encryptedIndividualList.size(); i++) { + if (Boolean.TRUE.equals(encryptedIndividualList.get(i).getIsSystemUser())) { + encryptedIndividualList.get(i) + .setUserId(Long.toString(userRequests.get(i).getId())); + encryptedIndividualList.get(i).setUserUuid(userRequests.get(i).getUuid()); + } + } individualRepository.save(encryptedIndividualList, properties.getUpdateUserIdTopic()); log.info("successfully created user for {} individuals", @@ -362,8 +436,24 @@ private void integrateWithUserService(IndividualBulkRequest request, encryptedIndividualList.size()); } } catch (Exception exception) { - log.error("error occurred while creating user", exception); + log.error("error occurred while creating user", ExceptionUtils.getStackTrace(exception)); } } } + Boolean isSmsEnabledForRole(IndividualRequest request) { + if (CollectionUtils.isEmpty(properties.getSmsDisabledRoles())) + return true; + List smsDisabledRoles = properties.getSmsDisabledRoles(); + List roleCodes = new ArrayList<>(); + if(request != null && request.getIndividual() != null && request.getIndividual().getUserDetails() != null + && request.getIndividual().getUserDetails().getRoles() != null) { + // get the role codes from the list of roles + roleCodes = request.getIndividual().getUserDetails().getRoles().stream().map(Role::getCode).collect(Collectors.toList()); + } + for (String smsDisabledRole : smsDisabledRoles) { + if (roleCodes.contains(smsDisabledRole)) + return false; + } + return true; + } } diff --git a/health-services/individual/src/main/java/org/egov/individual/service/UserIntegrationService.java b/health-services/individual/src/main/java/org/egov/individual/service/UserIntegrationService.java index 74c7fccf103..18e2323cc8d 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/UserIntegrationService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/UserIntegrationService.java @@ -11,7 +11,6 @@ import org.springframework.stereotype.Service; import java.util.List; -import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; @@ -29,7 +28,7 @@ public UserIntegrationService(UserService userService, IndividualProperties indi this.individualProperties = individualProperties; } - public Optional createUser(List validIndividuals, + public List createUser(List validIndividuals, RequestInfo requestInfo) { log.info("integrating with user service"); List userRequests = validIndividuals.stream() @@ -37,11 +36,11 @@ public Optional createUser(List validIndividuals, .collect(Collectors.toList()); return userRequests.stream().flatMap(userRequest -> userService.create( new CreateUserRequest(requestInfo, - userRequest)).stream()).collect(Collectors.toList()).stream().findFirst(); + userRequest)).stream()).collect(Collectors.toList()); } - public Optional updateUser(List validIndividuals, + public List updateUser(List validIndividuals, RequestInfo requestInfo) { log.info("updating the user in user service"); List userRequests = validIndividuals.stream() @@ -49,10 +48,10 @@ public Optional updateUser(List validIndividuals, .collect(Collectors.toList()); return userRequests.stream().flatMap(userRequest -> userService.update( new CreateUserRequest(requestInfo, - userRequest)).stream()).collect(Collectors.toList()).stream().findFirst(); + userRequest)).stream()).collect(Collectors.toList()); } - public Optional deleteUser(List validIndividuals, + public List deleteUser(List validIndividuals, RequestInfo requestInfo) { log.info("deleting the user in user service"); List userRequests = validIndividuals.stream() @@ -61,7 +60,7 @@ public Optional deleteUser(List validIndividuals, .collect(Collectors.toList()); return userRequests.stream().flatMap(userRequest -> userService.update( new CreateUserRequest(requestInfo, - userRequest)).stream()).collect(Collectors.toList()).stream().findFirst(); + userRequest)).stream()).collect(Collectors.toList()); } private Function toUserRequest() { diff --git a/health-services/individual/src/main/java/org/egov/individual/validators/IBoundaryValidator.java b/health-services/individual/src/main/java/org/egov/individual/validators/IBoundaryValidator.java new file mode 100644 index 00000000000..83eb2b343af --- /dev/null +++ b/health-services/individual/src/main/java/org/egov/individual/validators/IBoundaryValidator.java @@ -0,0 +1,129 @@ +package org.egov.individual.validators; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.core.Boundary; +import org.egov.common.models.individual.Individual; +import org.egov.common.models.individual.IndividualBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.individual.config.IndividualProperties; +import org.egov.individual.web.models.boundary.BoundaryResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +/** + * Validator class for validating individual boundaries. + */ +@Component +@Order(value = 4) +@Slf4j +public class IBoundaryValidator implements Validator { + + private final ServiceRequestClient serviceRequestClient; + + private final IndividualProperties individualProperties; + + /** + * Constructor to initialize the IBoundaryValidator. + * + * @param serviceRequestClient Service request client for making HTTP requests + * @param individualProperties Configuration properties for the individual module + */ + public IBoundaryValidator(ServiceRequestClient serviceRequestClient, IndividualProperties individualProperties) { + this.serviceRequestClient = serviceRequestClient; + this.individualProperties = individualProperties; + } + + /** + * Validates the individuals' boundaries. + * + * @param request the bulk request containing individuals + * @return a map containing individuals with their corresponding list of errors + */ + @Override + public Map> validate(IndividualBulkRequest request) { + log.debug("Validating individuals boundaries."); + // Create a HashMap to store error details for each individual + HashMap> errorDetailsMap = new HashMap<>(); + + // Filter individuals with non-null addresses + List entitiesWithValidBoundaries = request.getIndividuals().parallelStream() + .filter(individual -> !CollectionUtils.isEmpty(individual.getAddress())) + .collect(Collectors.toList()); + + Map> tenantIdIndividualMap = entitiesWithValidBoundaries.stream().collect(Collectors.groupingBy(Individual::getTenantId)); + + tenantIdIndividualMap.forEach((tenantId, individuals) -> { + // Group individuals by locality code + Map> boundaryCodeIndividualsMap = individuals.stream() + .flatMap(individual -> individual.getAddress().stream() + .filter(address -> Objects.nonNull(address.getLocality())) // Filter out addresses with null locality + .map(address -> new AbstractMap.SimpleEntry<>(address.getLocality().getCode(), individual))) // Map each address to its locality code and individual + .collect(Collectors.groupingBy(Map.Entry::getKey, // Group by locality code + Collectors.mapping(Map.Entry::getValue, Collectors.toList()))); // Collect individuals into a list for each locality code + + List boundaries = new ArrayList<>(boundaryCodeIndividualsMap.keySet()); + if(!CollectionUtils.isEmpty(boundaries)) { + try { + // Fetch boundary details from the service + log.debug("Fetching boundary details for tenantId: {}, boundaries: {}", tenantId, boundaries); + BoundaryResponse boundarySearchResponse = serviceRequestClient.fetchResult( + new StringBuilder(individualProperties.getBoundaryServiceHost() + + individualProperties.getBoundarySearchUrl() + +"?limit=" + boundaries.size() + + "&offset=0&tenantId=" + tenantId + + "&codes=" + String.join(",", boundaries)), + request.getRequestInfo(), + BoundaryResponse.class + ); + log.debug("Boundary details fetched successfully for tenantId: {}", tenantId); + + List invalidBoundaryCodes = new ArrayList<>(boundaries); + invalidBoundaryCodes.removeAll(boundarySearchResponse.getBoundary().stream() + .map(Boundary::getCode) + .collect(Collectors.toList()) + ); + + // Filter out individuals with invalid boundary codes + List individualsWithInvalidBoundaries = boundaryCodeIndividualsMap.entrySet().stream() + .filter(entry -> invalidBoundaryCodes.contains(entry.getKey())) // filter invalid boundary codes + .flatMap(entry -> entry.getValue().stream()) // Flatten the list of individuals + .collect(Collectors.toList()); + + + individualsWithInvalidBoundaries.forEach(individual -> { + // Create an error object for individuals with invalid boundaries + Error error = Error.builder() + .errorMessage("Boundary code does not exist in db") + .errorCode("NON_EXISTENT_ENTITY") + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException("NON_EXISTENT_ENTITY", "Boundary code does not exist in db")) + .build(); + // Populate error details for the individual + populateErrorDetails(individual, error, errorDetailsMap); + }); + + } catch (Exception e) { + log.error("Exception while searching boundaries for tenantId: {}", tenantId, e); + // Throw a custom exception if an error occurs during boundary search + throw new CustomException("BOUNDARY_SERVICE_SEARCH_ERROR","Error in while fetching boundaries from Boundary Service : " + e.getMessage()); + } + } + }); + + return errorDetailsMap; + } +} diff --git a/health-services/individual/src/main/java/org/egov/individual/validators/IExistentEntityValidator.java b/health-services/individual/src/main/java/org/egov/individual/validators/IExistentEntityValidator.java new file mode 100644 index 00000000000..39bb06f6ed8 --- /dev/null +++ b/health-services/individual/src/main/java/org/egov/individual/validators/IExistentEntityValidator.java @@ -0,0 +1,97 @@ +package org.egov.individual.validators; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.individual.Individual; +import org.egov.common.models.individual.IndividualBulkRequest; +import org.egov.common.models.individual.IndividualSearch; +import org.egov.common.validator.Validator; +import org.egov.individual.repository.IndividualRepository; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of entities with the given client reference IDs. + * This validator checks if the provided individual entities already exist in the database based on their client reference IDs. + * + * @author kanishq-egov + */ +@Component +@Order(value = 1) +@Slf4j +public class IExistentEntityValidator implements Validator { + + private final IndividualRepository individualRepository; + + /** + * Constructor to initialize the IndividualRepository dependency. + * + * @param individualRepository The repository for individual entities. + */ + public IExistentEntityValidator(IndividualRepository individualRepository) { + this.individualRepository = individualRepository; + } + + /** + * Validates the existence of entities with the given client reference IDs. + * This method checks if any of the individual entities in the request already exist in the database, + * based on their client reference IDs. If an entity is found to exist, an error is added to the error details map. + * + * @param request The bulk request containing individual entities. + * @return A map containing individual entities and their associated error details, if any. + */ + @Override + public Map> validate(IndividualBulkRequest request) { + // Map to hold individual entities and their associated error details + Map> errorDetailsMap = new HashMap<>(); + + // Get the list of individual entities from the request + List entities = request.getIndividuals(); + + // Extract client reference IDs from individual entities that do not have errors + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) // Filter out entities that already have errors + .map(Individual::getClientReferenceId) // Map to client reference IDs + .collect(Collectors.toList()); // Collect the IDs into a list + + // Create a map of client reference ID to Individual entity for easy lookup + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + + // Create a search object for querying entities by client reference IDs + IndividualSearch individualSearch = IndividualSearch.builder() + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search + .build(); + + // Check if the client reference ID list is not empty before querying the database + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing entities by client reference IDs + List existingClientReferenceIds = + individualRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, populate error details for uniqueness + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation + Error error = getErrorForUniqueEntity(); + // Populate error details for the individual entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); + }); + } + + // Return the map containing individual entities and their associated error details + return errorDetailsMap; + } + +} diff --git a/health-services/individual/src/main/java/org/egov/individual/validators/INonExistentEntityValidator.java b/health-services/individual/src/main/java/org/egov/individual/validators/INonExistentEntityValidator.java new file mode 100644 index 00000000000..02b5b128599 --- /dev/null +++ b/health-services/individual/src/main/java/org/egov/individual/validators/INonExistentEntityValidator.java @@ -0,0 +1,107 @@ +package org.egov.individual.validators; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.individual.Individual; +import org.egov.common.models.individual.IndividualBulkRequest; +import org.egov.common.models.individual.IndividualSearch; +import org.egov.common.validator.Validator; +import org.egov.individual.repository.IndividualRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; +import static org.egov.individual.Constants.GET_ID; + +/** + * Validator for checking the non-existence of individual entities. + * This validator checks if the provided individual entities do not already exist in the database. + * + * @author kanishq-egov + */ +@Component +@Order(value = 2) +@Slf4j +public class INonExistentEntityValidator implements Validator { + + private final IndividualRepository individualRepository; + + public INonExistentEntityValidator(IndividualRepository individualRepository) { + this.individualRepository = individualRepository; + } + + /** + * Validates the non-existence of entities based on their IDs and client reference IDs. + * + * @param request The bulk request containing individual entities. + * @return A map containing individual entities and their associated error details. + */ + @Override + public Map> validate(IndividualBulkRequest request) { + // Map to hold individual entities and their error details + Map> errorDetailsMap = new HashMap<>(); + // Get the list of individual entities from the request + List entities = request.getIndividuals(); + // Get the class of the individual entity + Class objClass = getObjClass(entities); + // Get the method for fetching the ID of the entity + Method idMethod = getMethod(GET_ID, objClass); + // Map to store entities by their IDs + Map eMap = getIdToObjMap( + entities.stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + // Lists to store IDs and client reference IDs + List idList = new ArrayList<>(); + List clientReferenceIdList = new ArrayList<>(); + // Extract IDs and client reference IDs from individual entities + entities.forEach(individual -> { + idList.add(individual.getId()); + clientReferenceIdList.add(individual.getClientReferenceId()); + }); + // Check if the entity map is not empty + if (!eMap.isEmpty()) { + + // Create a search object for querying existing entities + IndividualSearch individualSearch = IndividualSearch.builder() + .id(idList) + .clientReferenceId(clientReferenceIdList) + .build(); + + List existingEntities; + try { + // Query the repository to find existing entities + existingEntities = individualRepository.find(individualSearch, entities.size(), 0, + entities.get(0).getTenantId(), null, false).getResponse(); + } catch (Exception e) { + // Handle query builder exception + existingEntities = new ArrayList<>(); + log.error("Search failed for Individual with error: {}", e.getMessage(), e); + throw new CustomException("INDIVIDUAL_SEARCH_FAILED", "Search Failed for Individual, " + e.getMessage()); + } + // Check for non-existent entities + List nonExistentEntities = checkNonExistentEntities(eMap, + existingEntities, idMethod); + // Populate error details for non-existent entities + nonExistentEntities.forEach(entity -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + + return errorDetailsMap; + } +} + diff --git a/health-services/individual/src/main/java/org/egov/individual/validators/NonExistentEntityValidator.java b/health-services/individual/src/main/java/org/egov/individual/validators/NonExistentEntityValidator.java index dd4d24268f3..fa9b3617ca9 100644 --- a/health-services/individual/src/main/java/org/egov/individual/validators/NonExistentEntityValidator.java +++ b/health-services/individual/src/main/java/org/egov/individual/validators/NonExistentEntityValidator.java @@ -4,8 +4,10 @@ import org.egov.common.models.Error; import org.egov.common.models.individual.Individual; import org.egov.common.models.individual.IndividualBulkRequest; +import org.egov.common.models.individual.IndividualSearch; import org.egov.common.validator.Validator; import org.egov.individual.repository.IndividualRepository; +import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -56,10 +58,31 @@ public Map> validate(IndividualBulkRequest request) { Method idMethod = getMethod(GET_ID, objClass); Map iMap = getIdToObjMap(individuals .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + // Lists to store IDs and client reference IDs + List idList = new ArrayList<>(); + List clientReferenceIdList = new ArrayList<>(); + // Extract IDs and client reference IDs from individual entities + individuals.forEach(individual -> { + idList.add(individual.getId()); + clientReferenceIdList.add(individual.getClientReferenceId()); + }); if (!iMap.isEmpty()) { - List individualIds = new ArrayList<>(iMap.keySet()); - List existingIndividuals = individualRepository.findById(individualIds, - getIdFieldName(idMethod), false); + // Create a search object for querying existing entities + IndividualSearch individualSearch = IndividualSearch.builder() + .id(idList) + .clientReferenceId(clientReferenceIdList) + .build(); + + List existingIndividuals; + try { + // Query the repository to find existing entities + existingIndividuals = individualRepository.find(individualSearch, individuals.size(), 0, + individuals.get(0).getTenantId(), null, false).getResponse(); + } catch (Exception e) { + // Handle query builder exception + log.error("Search failed for Individual with error: {}", e.getMessage(), e); + throw new CustomException("INDIVIDUAL_SEARCH_FAILED", "Search Failed for Individual, " + e.getMessage()); + } List nonExistentIndividuals = checkNonExistentEntities(iMap, existingIndividuals, idMethod); nonExistentIndividuals.forEach(individual -> { diff --git a/health-services/individual/src/main/java/org/egov/individual/validators/RowVersionValidator.java b/health-services/individual/src/main/java/org/egov/individual/validators/RowVersionValidator.java index 7f73606ec10..858e525d8e0 100644 --- a/health-services/individual/src/main/java/org/egov/individual/validators/RowVersionValidator.java +++ b/health-services/individual/src/main/java/org/egov/individual/validators/RowVersionValidator.java @@ -49,7 +49,7 @@ public Map> validate(IndividualBulkRequest request) { if (!iMap.isEmpty()) { List individualIds = new ArrayList<>(iMap.keySet()); List existingIndividuals = individualRepository.findById(individualIds, - getIdFieldName(idMethod), false); + getIdFieldName(idMethod), false).getResponse(); List individualsWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(iMap, existingIndividuals, idMethod); individualsWithMismatchedRowVersion.forEach(individual -> { diff --git a/health-services/individual/src/main/java/org/egov/individual/web/controllers/IndividualApiController.java b/health-services/individual/src/main/java/org/egov/individual/web/controllers/IndividualApiController.java index b7f75cdc337..aeb7668e419 100644 --- a/health-services/individual/src/main/java/org/egov/individual/web/controllers/IndividualApiController.java +++ b/health-services/individual/src/main/java/org/egov/individual/web/controllers/IndividualApiController.java @@ -1,38 +1,37 @@ package org.egov.individual.web.controllers; +import java.util.List; + import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; import org.egov.common.models.individual.Individual; import org.egov.common.models.individual.IndividualBulkRequest; import org.egov.common.models.individual.IndividualBulkResponse; import org.egov.common.models.individual.IndividualRequest; import org.egov.common.models.individual.IndividualResponse; +import org.egov.common.models.individual.IndividualSearchRequest; import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; import org.egov.individual.config.IndividualProperties; import org.egov.individual.service.IndividualService; -import org.egov.individual.web.models.IndividualSearchRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.util.List; -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") @Controller @Validated @@ -85,14 +84,22 @@ public ResponseEntity individualV1BulkCreatePost(@ApiParam(value = } @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) - public ResponseEntity individualV1SearchPost(@ApiParam(value = "Individual details.", required = true) @Valid @RequestBody IndividualSearchRequest request, @NotNull - @Min(0) - @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull - @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @Size(min = 2, max = 1000) @RequestParam(value = "tenantId", required = true) String tenantId, @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) { - List individuals = individualService.search(request.getIndividual(), limit, offset, tenantId, - lastChangedSince, includeDeleted,request.getRequestInfo()); + public ResponseEntity individualV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Individual details.", required = true) @Valid @RequestBody IndividualSearchRequest request + ) { + SearchResponse searchResponse = individualService.search( + request.getIndividual(), + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted(), + request.getRequestInfo() + ); IndividualBulkResponse response = IndividualBulkResponse.builder() - .individual(individuals) + .individual(searchResponse.getResponse()) + .totalCount(searchResponse.getTotalCount()) .responseInfo(ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), true)) .build(); return ResponseEntity.status(HttpStatus.OK).body(response); diff --git a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearchRequest.java b/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearchRequest.java deleted file mode 100644 index d83c7c495ce..00000000000 --- a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearchRequest.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.egov.individual.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -/** -* IndividualSearchRequest -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class IndividualSearchRequest { - @JsonProperty("RequestInfo") - @NotNull - - @Valid - - - private org.egov.common.contract.request.RequestInfo requestInfo = null; - - @JsonProperty("Individual") - @NotNull - - @Valid - - - private IndividualSearch individual = null; - - -} - diff --git a/health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundaryRequest.java b/health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundaryRequest.java new file mode 100644 index 00000000000..dd717d007ce --- /dev/null +++ b/health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundaryRequest.java @@ -0,0 +1,38 @@ +package org.egov.individual.web.models.boundary; + +import java.util.List; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryRequest + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @Valid + @NotNull + @JsonProperty("Boundary") + @Size(min = 1, max = 300) + private List boundary = null; + +} diff --git a/health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundaryResponse.java b/health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundaryResponse.java new file mode 100644 index 00000000000..3ea2bed112d --- /dev/null +++ b/health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundaryResponse.java @@ -0,0 +1,44 @@ +package org.egov.individual.web.models.boundary; + +import java.util.ArrayList; +import java.util.List; +import jakarta.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryResponse + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Boundary") + @Valid + private List boundary = null; + + + public BoundaryResponse addBoundaryItem(Boundary boundaryItem) { + if (this.boundary == null) { + this.boundary = new ArrayList<>(); + } + this.boundary.add(boundaryItem); + return this; + } + +} diff --git a/health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundarySearchCriteria.java b/health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundarySearchCriteria.java new file mode 100644 index 00000000000..bb8b0c364fd --- /dev/null +++ b/health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundarySearchCriteria.java @@ -0,0 +1,37 @@ +package org.egov.individual.web.models.boundary; + +import java.util.List; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundarySearchCriteria { + + @NotNull + @Size(min = 1) + @JsonProperty("codes") + private List codes; + + @NotNull + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} diff --git a/health-services/individual/src/main/resources/application.properties b/health-services/individual/src/main/resources/application.properties index 14813237ab4..f096fe456f8 100644 --- a/health-services/individual/src/main/resources/application.properties +++ b/health-services/individual/src/main/resources/application.properties @@ -91,6 +91,7 @@ user.service.account.locked=false #Notification notification.sms.enabled=true kafka.topics.notification.sms=egov.core.notification.sms +notification.sms.disabled.roles=ORG_ADMIN #Localization config egov.localization.host=https://works-dev.digit.org/ @@ -98,3 +99,7 @@ egov.localization.context.path=localization/messages/v1 egov.localization.search.endpoint=/_search egov.localization.statelevel=true +# BOUNDARY SERVICE +egov.boundary.host=http://localhost:8081 +egov.boundary.search.url=/boundary-service/boundary/_search +egov.boundary.hierarchy=HCM-Moz-Hierarchy \ No newline at end of file diff --git a/health-services/individual/src/main/resources/db/Dockerfile b/health-services/individual/src/main/resources/db/Dockerfile index 60fc07ce69f..e7da01d7f0b 100644 --- a/health-services/individual/src/main/resources/db/Dockerfile +++ b/health-services/individual/src/main/resources/db/Dockerfile @@ -1,4 +1,4 @@ -FROM egovio/flyway:4.1.2 +FROM egovio/flyway:10.7.1 COPY ./migration/main /flyway/sql @@ -6,4 +6,4 @@ COPY migrate.sh /usr/bin/migrate.sh RUN chmod +x /usr/bin/migrate.sh -CMD ["/usr/bin/migrate.sh"] \ No newline at end of file +ENTRYPOINT ["/usr/bin/migrate.sh"] \ No newline at end of file diff --git a/health-services/individual/src/main/resources/db/migrate.sh b/health-services/individual/src/main/resources/db/migrate.sh index 43960b25cdb..f9d6617822c 100644 --- a/health-services/individual/src/main/resources/db/migrate.sh +++ b/health-services/individual/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/individual/src/main/resources/db/migration/main/V20230515111200__add_userdetails_in_individual_ddl.sql b/health-services/individual/src/main/resources/db/migration/main/V20230515111200__add_userdetails_in_individual_ddl.sql new file mode 100644 index 00000000000..6623ced3cd9 --- /dev/null +++ b/health-services/individual/src/main/resources/db/migration/main/V20230515111200__add_userdetails_in_individual_ddl.sql @@ -0,0 +1,4 @@ +ALTER TABLE INDIVIDUAL ADD COLUMN username character varying(64); +ALTER TABLE INDIVIDUAL ADD COLUMN password character varying(200); +ALTER TABLE INDIVIDUAL ADD COLUMN type character varying(64); +ALTER TABLE INDIVIDUAL ADD COLUMN roles jsonb; \ No newline at end of file diff --git a/health-services/individual/src/main/resources/db/migration/main/V20230526162410__alter_individual_gender_ddl.sql b/health-services/individual/src/main/resources/db/migration/main/V20230526162410__alter_individual_gender_ddl.sql new file mode 100644 index 00000000000..f8aac1bc467 --- /dev/null +++ b/health-services/individual/src/main/resources/db/migration/main/V20230526162410__alter_individual_gender_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE INDIVIDUAL ALTER COLUMN gender TYPE character varying(20); \ No newline at end of file diff --git a/health-services/individual/src/main/resources/db/migration/main/V20230531131000__add_userUuid_in_individual_ddl.sql b/health-services/individual/src/main/resources/db/migration/main/V20230531131000__add_userUuid_in_individual_ddl.sql new file mode 100644 index 00000000000..b2ba6fbe1b3 --- /dev/null +++ b/health-services/individual/src/main/resources/db/migration/main/V20230531131000__add_userUuid_in_individual_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE INDIVIDUAL ADD COLUMN userUuid character varying(64); \ No newline at end of file diff --git a/health-services/individual/src/main/resources/db/migration/main/V20230601163900__add_isSystemUserActive_in_individual_ddl.sql b/health-services/individual/src/main/resources/db/migration/main/V20230601163900__add_isSystemUserActive_in_individual_ddl.sql new file mode 100644 index 00000000000..3aefbd11705 --- /dev/null +++ b/health-services/individual/src/main/resources/db/migration/main/V20230601163900__add_isSystemUserActive_in_individual_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE INDIVIDUAL ADD COLUMN isSystemUserActive boolean; \ No newline at end of file diff --git a/health-services/individual/src/main/resources/db/migration/main/V20230616153900__add_client_audit_details_in_individual_ddl.sql b/health-services/individual/src/main/resources/db/migration/main/V20230616153900__add_client_audit_details_in_individual_ddl.sql new file mode 100644 index 00000000000..b8ed09c5ec7 --- /dev/null +++ b/health-services/individual/src/main/resources/db/migration/main/V20230616153900__add_client_audit_details_in_individual_ddl.sql @@ -0,0 +1,2 @@ +ALTER TABLE INDIVIDUAL ADD COLUMN clientCreatedTime bigint; +ALTER TABLE INDIVIDUAL ADD COLUMN clientLastModifiedTime bigint; \ No newline at end of file diff --git a/health-services/individual/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_individual_ddl.sql b/health-services/individual/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_individual_ddl.sql new file mode 100644 index 00000000000..b4c0706bf30 --- /dev/null +++ b/health-services/individual/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_individual_ddl.sql @@ -0,0 +1,2 @@ +ALTER TABLE INDIVIDUAL ADD COLUMN IF NOT EXISTS clientCreatedBy character varying(64); +ALTER TABLE INDIVIDUAL ADD COLUMN IF NOT EXISTS clientLastModifiedBy character varying(64); diff --git a/health-services/individual/src/main/resources/individual-persister.yml b/health-services/individual/src/main/resources/individual-persister.yml index de75eee7c94..de6ff66723b 100644 --- a/health-services/individual/src/main/resources/individual-persister.yml +++ b/health-services/individual/src/main/resources/individual-persister.yml @@ -26,11 +26,12 @@ serviceMaps: - jsonPath: $.*.address.*.street - jsonPath: $.*.address.*.locality.code - jsonPath: $.*.address.*.ward.code - - query: INSERT INTO individual(id, userId, clientReferenceId, tenantId, givenName, familyName, otherNames, dateOfBirth, gender, bloodGroup, mobileNumber, altContactNumber, email, fatherName, husbandName, photo, additionalDetails, createdBy, lastModifiedBy, createdTime, lastModifiedTime, rowVersion, isDeleted, individualId, relationship) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + - query: INSERT INTO individual(id, userId, userUuid, clientReferenceId, tenantId, givenName, familyName, otherNames, dateOfBirth, gender, bloodGroup, mobileNumber, altContactNumber, email, fatherName, husbandName, photo, additionalDetails, createdBy, lastModifiedBy, createdTime, lastModifiedTime, rowVersion, isDeleted, individualId, relationship, isSystemUser, username, password, type, roles) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); basePath: $.* jsonMaps: - jsonPath: $.*.id - jsonPath: $.*.userId + - jsonPath: $.*.userUuid - jsonPath: $.*.clientReferenceId - jsonPath: $.*.tenantId - jsonPath: $.*.name.givenName @@ -57,6 +58,13 @@ serviceMaps: - jsonPath: $.*.isDeleted - jsonPath: $.*.individualId - jsonPath: $.*.relationship + - jsonPath: $.*.isSystemUser + - jsonPath: $.*.userDetails.username + - jsonPath: $.*.userDetails.password + - jsonPath: $.*.userDetails.type + - jsonPath: $.*.userDetails.roles + type: JSON + dbType: JSONB - query: INSERT INTO individual_address(individualId, addressId, type, createdBy, lastModifiedBy, createdTime, lastModifiedTime, isDeleted) VALUES (?, ?, ?, ?, ?, ?, ?, ?); basePath: $.*.address.* jsonMaps: @@ -101,10 +109,11 @@ serviceMaps: fromTopic: update-individual-topic isTransaction: true queryMaps: - - query: UPDATE individual SET userId=?, tenantId=?, givenName=?, familyName=?, otherNames=?, dateOfBirth=?, Gender=?, bloodGroup=?, mobileNumber=?, altContactNumber=?, email=?, fatherName=?, husbandName=?, relationship=?, photo=?, additionalDetails=?, lastModifiedBy=?, lastModifiedTime=?, rowVersion=? WHERE id=? AND isDeleted=false; + - query: UPDATE individual SET userId=?, userUuid=?, tenantId=?, givenName=?, familyName=?, otherNames=?, dateOfBirth=?, Gender=?, bloodGroup=?, mobileNumber=?, altContactNumber=?, email=?, fatherName=?, husbandName=?, relationship=?, photo=?, additionalDetails=?, lastModifiedBy=?, lastModifiedTime=?, rowVersion=?, username = ?, password = ?, type = ?, roles = ? WHERE id=? AND isDeleted=false; basePath: $.* jsonMaps: - jsonPath: $.*.userId + - jsonPath: $.*.userUuid - jsonPath: $.*.tenantId - jsonPath: $.*.name.givenName - jsonPath: $.*.name.familyName @@ -126,6 +135,12 @@ serviceMaps: - jsonPath: $.*.auditDetails.lastModifiedBy - jsonPath: $.*.auditDetails.lastModifiedTime - jsonPath: $.*.rowVersion + - jsonPath: $.*.userDetails.username + - jsonPath: $.*.userDetails.password + - jsonPath: $.*.userDetails.type + - jsonPath: $.*.userDetails.roles + type: JSON + dbType: JSONB - jsonPath: $.*.id - query: INSERT INTO address(id, clientReferenceId, tenantId, doorNo, latitude, longitude, locationAccuracy, type, addressLine1, addressLine2, landmark, city, pincode, buildingName, street, localityCode, wardCode) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (id) DO UPDATE SET doorno=?, latitude=?, longitude=?, locationaccuracy=?, type=?, addressline1=?, addressline2=?, landmark=?, city=?, pincode=?, buildingname=?, street=?, localitycode=?, wardCode=?; basePath: $.*.address.* @@ -174,7 +189,7 @@ serviceMaps: - jsonPath: $.*.address.*.isDeleted - jsonPath: $.*.address.*.auditDetails.lastModifiedBy - jsonPath: $.*.address.*.auditDetails.lastModifiedTime - - query: INSERT INTO individual_identifier(id, clientReferenceId, individualId, identifierType, identifierId, createdBy, lastModifiedBy, createdTime, lastModifiedTime, isDeleted) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (id) WHERE isDeleted=false DO UPDATE SET identifierId = ?, lastModifiedBy = ?, lastModifiedTime = ?; + - query: INSERT INTO individual_identifier(id, clientReferenceId, individualId, identifierType, identifierId, createdBy, lastModifiedBy, createdTime, lastModifiedTime, isDeleted) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (id) WHERE isDeleted=false DO UPDATE SET identifierId = ?, identifierType = ?, lastModifiedBy = ?, lastModifiedTime = ?; basePath: $.*.identifiers.* jsonMaps: - jsonPath: $.*.identifiers.*.id @@ -188,6 +203,7 @@ serviceMaps: - jsonPath: $.*.identifiers.*.auditDetails.lastModifiedTime - jsonPath: $.*.identifiers.*.isDeleted - jsonPath: $.*.identifiers.*.identifierId + - jsonPath: $.*.identifiers.*.identifierType - jsonPath: $.*.identifiers.*.auditDetails.lastModifiedBy - jsonPath: $.*.identifiers.*.auditDetails.lastModifiedTime - query: INSERT INTO individual_skill(id, clientReferenceId, individualId, type, level, experience, createdBy, lastModifiedBy, createdTime, lastModifiedTime, isDeleted) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (id) WHERE isDeleted=false DO UPDATE SET type = ?, level = ?, experience = ?, lastModifiedBy = ?, lastModifiedTime = ?; @@ -244,4 +260,16 @@ serviceMaps: - jsonPath: $.*.skills.*.auditDetails.lastModifiedBy - jsonPath: $.*.skills.*.auditDetails.lastModifiedTime - jsonPath: $.*.skills.*.isDeleted - - jsonPath: $.*.skills.*.id \ No newline at end of file + - jsonPath: $.*.skills.*.id + + - version: 1.0 + description: Updates userId and userUuid received from user-service into an individual + fromTopic: update-user-id-topic + isTransaction: true + queryMaps: + - query: UPDATE individual SET userId=?, userUuid=? WHERE id=?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.userId + - jsonPath: $.*.userUuid + - jsonPath: $.*.id \ No newline at end of file diff --git a/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchRequestTestBuilder.java b/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchRequestTestBuilder.java index ef9386b7956..850a4cdb2a5 100644 --- a/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchRequestTestBuilder.java +++ b/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchRequestTestBuilder.java @@ -1,19 +1,19 @@ package org.egov.individual.helper; -import org.egov.common.contract.request.RequestInfo; -import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.individual.Gender; -import org.egov.common.models.individual.Identifier; -import org.egov.common.models.individual.Name; -import org.egov.individual.web.models.IndividualSearch; -import org.egov.individual.web.models.IndividualSearchRequest; - import java.time.LocalDate; import java.time.ZoneId; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.individual.Gender; +import org.egov.common.models.individual.Identifier; +import org.egov.common.models.individual.IndividualSearch; +import org.egov.common.models.individual.IndividualSearchRequest; +import org.egov.common.models.individual.Name; + public class IndividualSearchRequestTestBuilder { private IndividualSearchRequest.IndividualSearchRequestBuilder builder; diff --git a/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchTestBuilder.java b/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchTestBuilder.java index 6db1b119462..ffcc1ee9152 100644 --- a/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchTestBuilder.java +++ b/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchTestBuilder.java @@ -4,7 +4,7 @@ import org.egov.common.models.individual.Gender; import org.egov.common.models.individual.Identifier; import org.egov.common.models.individual.Name; -import org.egov.individual.web.models.IndividualSearch; +import org.egov.common.models.individual.IndividualSearch; import java.time.LocalDate; import java.time.ZoneId; @@ -53,7 +53,17 @@ public IndividualSearchTestBuilder byClientReferenceId(String... args) { this.builder.clientReferenceId(ids); return this; } + public IndividualSearchTestBuilder byUserUUID(String... args) { + ArrayList ids = new ArrayList<>(); + if (args != null && args.length > 0) { + ids.add(args[0]); + } else { + ids.add("some-user-uuid"); + } + this.builder.userUuid(ids); + return this; + } public IndividualSearchTestBuilder byName() { this.builder.name(Name.builder() diff --git a/health-services/individual/src/test/java/org/egov/individual/repository/IndividualRepositoryTest.java b/health-services/individual/src/test/java/org/egov/individual/repository/IndividualRepositoryTest.java index 3e73c932c08..1da11ed66a6 100644 --- a/health-services/individual/src/test/java/org/egov/individual/repository/IndividualRepositoryTest.java +++ b/health-services/individual/src/test/java/org/egov/individual/repository/IndividualRepositoryTest.java @@ -9,7 +9,7 @@ import org.egov.individual.repository.rowmapper.AddressRowMapper; import org.egov.individual.repository.rowmapper.IdentifierRowMapper; import org.egov.individual.repository.rowmapper.IndividualRowMapper; -import org.egov.individual.web.models.IndividualSearch; +import org.egov.common.models.individual.IndividualSearch; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -19,6 +19,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.test.util.ReflectionTestUtils; @@ -69,17 +70,25 @@ void shouldFindByIdFromDbAndReturnAllTheDependentEntitiesAsWellIfPresent() throw Individual individual = IndividualTestBuilder.builder() .withId() .build(); + when(namedParameterJdbcTemplate.query(anyString(), anyMap(), any(IndividualRowMapper.class))) .thenReturn(Collections.singletonList(individual)); + when(namedParameterJdbcTemplate.query(anyString(), anyMap(), any(ResultSetExtractor.class))).thenReturn(0L); + individualRepository.findById(Arrays.asList("some-id"), "id", false); verify(namedParameterJdbcTemplate, times(1)) .query(anyString(), anyMap(), any(IndividualRowMapper.class)); + verify(namedParameterJdbcTemplate, times(1)) .query(anyString(), anyMap(), any(AddressRowMapper.class)); + verify(namedParameterJdbcTemplate, times(1)) .query(anyString(), anyMap(), any(IdentifierRowMapper.class)); + + verify(namedParameterJdbcTemplate, times(1)) + .query(anyString(), anyMap(), any(ResultSetExtractor.class)); } @Test @@ -88,6 +97,7 @@ void shouldFindOtherParamsFromDbAndReturnAllTheDependentEntitiesAsWellIfPresent( IndividualSearch individualSearch = IndividualSearchTestBuilder.builder() .byId() .byClientReferenceId() + .byUserUUID() .byGender() .byName() .byDateOfBirth() @@ -96,9 +106,12 @@ void shouldFindOtherParamsFromDbAndReturnAllTheDependentEntitiesAsWellIfPresent( Individual individual = IndividualTestBuilder.builder() .withId() .build(); + when(namedParameterJdbcTemplate.query(anyString(), anyMap(), any(IndividualRowMapper.class))) .thenReturn(Collections.singletonList(individual)); + when(namedParameterJdbcTemplate.query(anyString(), anyMap(), any(ResultSetExtractor.class))).thenReturn(0L); + individualRepository.find(individualSearch, 2, 0, "default", null, true); @@ -108,6 +121,9 @@ void shouldFindOtherParamsFromDbAndReturnAllTheDependentEntitiesAsWellIfPresent( .query(anyString(), anyMap(), any(AddressRowMapper.class)); verify(namedParameterJdbcTemplate, times(1)) .query(anyString(), anyMap(), any(IdentifierRowMapper.class)); + verify(namedParameterJdbcTemplate, times(1)) + .query(anyString(), anyMap(), any(ResultSetExtractor.class)); + } @Test @@ -145,6 +161,7 @@ void shouldFindOtherParamsAndIdentifierFromDbAndReturnAllTheDependentEntitiesAsW IndividualSearch individualSearch = IndividualSearchTestBuilder.builder() .byId() .byClientReferenceId() + .byUserUUID() .byGender() .byName() .byDateOfBirth() diff --git a/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceSearchTest.java b/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceSearchTest.java index 9f52892600a..43ec00dd0e3 100644 --- a/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceSearchTest.java +++ b/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceSearchTest.java @@ -3,10 +3,13 @@ import org.egov.common.contract.request.RequestInfo; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.individual.IndividualSearch; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.individual.Individual; import org.egov.common.service.IdGenService; import org.egov.individual.helper.IndividualSearchTestBuilder; +import org.egov.individual.helper.IndividualTestBuilder; import org.egov.individual.repository.IndividualRepository; -import org.egov.individual.web.models.IndividualSearch; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -14,8 +17,12 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import java.util.Collections; + import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.times; @@ -46,6 +53,11 @@ void shouldSearchOnlyByIdIfOnlyIdIsPresent() throws QueryBuilderException { .build(); RequestInfo requestInfo = RequestInfoTestBuilder.builder().withCompleteRequestInfo().build(); + when(individualRepository.findById(anyList(), anyString(), anyBoolean())) + .thenReturn(SearchResponse.builder().totalCount(1L).response(Collections.singletonList(IndividualTestBuilder.builder() + .withId("some-id") + .build())).build()); + individualService.search(individualSearch, 0, 10, "default", null, false,requestInfo); @@ -60,9 +72,18 @@ void shouldNotThrowExceptionIfArrayIsNull() throws QueryBuilderException { .byNullId() .build(); RequestInfo requestInfo = RequestInfoTestBuilder.builder().withCompleteRequestInfo().build(); + when(encryptionService.encrypt(any(IndividualSearch.class), any(String.class))).thenReturn(individualSearch); + + when(individualRepository.find(any(IndividualSearch.class), anyInt(), anyInt(), anyString(), + any(), anyBoolean())).thenReturn(SearchResponse.builder() + .totalCount(1L) + .response(Collections.singletonList(IndividualTestBuilder.builder() + .withId("some-id") + .build())).build()); + individualService.search(individualSearch, 0, 10, - "default", null, false,requestInfo); + "default", null, false, requestInfo); verify(individualRepository, times(0)).findById(anyList(), eq("id"), anyBoolean()); @@ -76,6 +97,11 @@ void shouldSearchByOnlyClientReferenceIdIfOnlyClientReferenceIdIsPresent() throw .build(); RequestInfo requestInfo = RequestInfoTestBuilder.builder().withCompleteRequestInfo().build(); + when(individualRepository.findById(anyList(), anyString(), anyBoolean())) + .thenReturn(SearchResponse.builder().response(Collections.singletonList(IndividualTestBuilder.builder() + .withId("some-id") + .build())).build()); + individualService.search(individualSearch, 0, 10, "default", null, false,requestInfo); @@ -92,7 +118,12 @@ void shouldNotCallFindByIdIfParametersOtherThanIdArePresent() throws QueryBuilde .build(); RequestInfo requestInfo = RequestInfoTestBuilder.builder().withCompleteRequestInfo().build(); + + when(individualRepository.find(any(IndividualSearch.class), anyInt(), anyInt(), anyString(), any(), anyBoolean())) + .thenReturn(SearchResponse.builder().build()); + when(encryptionService.encrypt(any(IndividualSearch.class), any(String.class))).thenReturn(individualSearch); + individualService.search(individualSearch, 0, 10, "default", null, false,requestInfo); @@ -109,6 +140,12 @@ void shouldCallFindIfParametersOtherThanIdArePresent() throws QueryBuilderExcept .build(); RequestInfo requestInfo = RequestInfoTestBuilder.builder().withCompleteRequestInfo().build(); when(encryptionService.encrypt(any(IndividualSearch.class), any(String.class))).thenReturn(individualSearch); + + when(individualRepository.find(any(IndividualSearch.class), anyInt(), anyInt(), anyString(), + any(), anyBoolean())).thenReturn(SearchResponse.builder().totalCount(1L).response(Collections.singletonList(IndividualTestBuilder.builder() + .withId("some-id") + .build())).build()); + individualService.search(individualSearch, 0, 10, "default", null, false,requestInfo); diff --git a/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceTest.java b/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceTest.java index 231aa15f8ae..cc2a2c55ca8 100644 --- a/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceTest.java +++ b/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceTest.java @@ -38,7 +38,10 @@ import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class IndividualServiceTest { diff --git a/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceUpdateTest.java b/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceUpdateTest.java index f1bfbe7d97a..7bb2c142e30 100644 --- a/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceUpdateTest.java +++ b/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceUpdateTest.java @@ -1,6 +1,8 @@ package org.egov.individual.service; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.individual.Identifier; import org.egov.common.models.individual.Individual; import org.egov.common.models.individual.IndividualBulkRequest; import org.egov.common.models.individual.IndividualRequest; @@ -41,7 +43,10 @@ import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class IndividualServiceUpdateTest { @@ -140,9 +145,14 @@ void shouldThrowExceptionIfEntitiesDoNotExistInDb() { void shouldCheckRowVersionsIfEntitiesAreValid() { Individual requestIndividual = IndividualTestBuilder.builder() .withClientReferenceId() + .withId("some-id") .withName() .withTenantId() .withAddress() + .withIdentifiers(Identifier.builder() + .id("some-id") + .identifierId("some-id") + .identifierType("some-type").build()) .withRowVersion() .build(); IndividualRequest request = IndividualRequestTestBuilder.builder() @@ -152,14 +162,24 @@ void shouldCheckRowVersionsIfEntitiesAreValid() { List individualsInDb = new ArrayList<>(); individualsInDb.add(IndividualTestBuilder.builder() .withClientReferenceId() - .withId() + .withId("some-id") .withName() .withTenantId() .withAddress() + .withIdentifiers(Identifier.builder() + .id("some-id") + .individualId("some-id") + .identifierId("some-id") + .identifierType("some-type").build()) .withRowVersion() .withAuditDetails() .build()); + + when(individualRepository.findById(anyList(),eq("id"),eq(false))).thenReturn(SearchResponse.builder() + .totalCount(Long.valueOf(individualsInDb.size())) + .response(individualsInDb) + .build()); when(encryptionService.encrypt(any(IndividualBulkRequest.class), anyList(), any(String.class), anyBoolean())).thenReturn(Collections.singletonList(requestIndividual)); @@ -203,6 +223,11 @@ void shouldSaveTheUpdatedEntities() { .withName("some-new-family-name", "some-new-given-name") .withTenantId() .withAddress() + .withId("some-id") + .withIdentifiers(Identifier.builder() + .id("some-id") + .identifierId("some-id") + .identifierType("some-type").build()) .withRowVersion() .build(); IndividualRequest request = IndividualRequestTestBuilder.builder() @@ -212,14 +237,23 @@ void shouldSaveTheUpdatedEntities() { List individualsInDb = new ArrayList<>(); individualsInDb.add(IndividualTestBuilder.builder() .withClientReferenceId() - .withId() + .withId("some-id") .withName() .withTenantId() .withAddress() + .withIdentifiers(Identifier.builder() + .id("some-id") + .individualId("some-id") + .identifierId("some-id") + .identifierType("some-type").build()) .withRowVersion() .withAuditDetails() .build()); + when(individualRepository.findById(anyList(),eq("id"),eq(false))).thenReturn(SearchResponse.builder() + .totalCount(Long.valueOf(individualsInDb.size())) + .response(individualsInDb) + .build()); when(encryptionService.encrypt(any(IndividualBulkRequest.class), anyList(), any(String.class), anyBoolean())).thenReturn(Collections.singletonList(requestIndividual)); List result = individualService.update(request); diff --git a/health-services/individual/src/test/java/org/egov/individual/validator/NonExistentEntityValidatorTest.java b/health-services/individual/src/test/java/org/egov/individual/validator/NonExistentEntityValidatorTest.java index c405c4da68d..06ec0dc7f1c 100644 --- a/health-services/individual/src/test/java/org/egov/individual/validator/NonExistentEntityValidatorTest.java +++ b/health-services/individual/src/test/java/org/egov/individual/validator/NonExistentEntityValidatorTest.java @@ -2,11 +2,13 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.individual.Address; import org.egov.common.models.individual.AddressType; import org.egov.common.models.individual.Identifier; import org.egov.common.models.individual.Individual; import org.egov.common.models.individual.IndividualBulkRequest; +import org.egov.common.models.individual.IndividualSearch; import org.egov.common.models.individual.Skill; import org.egov.individual.helper.IndividualBulkRequestTestBuilder; import org.egov.individual.helper.IndividualTestBuilder; @@ -20,7 +22,6 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -28,6 +29,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyString; @@ -65,7 +67,13 @@ void shouldNotGiveErrorWhenEntityExists() { IndividualBulkRequest individualBulkRequest = IndividualBulkRequestTestBuilder.builder().withIndividuals(individual).build(); List existingIndividuals = new ArrayList<>(); existingIndividuals.add(individual); - lenient().when(individualRepository.findById(anyList(), anyString(), eq(false))).thenReturn(existingIndividuals); + lenient().when(individualRepository.find(any(), any(), any(), any(), any(), any(Boolean.class))) + .thenReturn( + SearchResponse.builder() + .totalCount(Long.valueOf(existingIndividuals.size())) + .response(existingIndividuals) + .build() + ); assertTrue(nonExistentEntityValidator.validate(individualBulkRequest).isEmpty()); } @@ -77,7 +85,8 @@ void shouldGiveErrorWhenEntityDoesNotExist() { .withId("some-id") .build()) .build(); - when(individualRepository.findById(anyList(), anyString(), anyBoolean())).thenReturn(Collections.emptyList()); + when(individualRepository.find(any(), any(), any(), any(), any(), any(Boolean.class))) + .thenReturn(SearchResponse.builder().build()); Map> errorDetailsMap = new HashMap<>(); errorDetailsMap = nonExistentEntityValidator.validate(individualBulkRequest); List errorList = errorDetailsMap.values().stream().flatMap(Collection::stream).collect(Collectors.toList()); diff --git a/health-services/individual/src/test/java/org/egov/individual/validator/RowVersionValidatorTest.java b/health-services/individual/src/test/java/org/egov/individual/validator/RowVersionValidatorTest.java index 3f02a431ba8..93eba62128a 100644 --- a/health-services/individual/src/test/java/org/egov/individual/validator/RowVersionValidatorTest.java +++ b/health-services/individual/src/test/java/org/egov/individual/validator/RowVersionValidatorTest.java @@ -2,6 +2,7 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.individual.Address; import org.egov.common.models.individual.AddressType; import org.egov.common.models.individual.Identifier; @@ -64,7 +65,10 @@ void shouldNotGiveErrorWhenRowVersionMatches() { IndividualBulkRequest individualBulkRequest = IndividualBulkRequestTestBuilder.builder().withIndividuals(individual).build(); List existingIndividuals = new ArrayList<>(); existingIndividuals.add(individual); - lenient().when(individualRepository.findById(anyList(), anyString(), eq(false))).thenReturn(existingIndividuals); + lenient().when(individualRepository.findById(anyList(), anyString(), eq(false))).thenReturn(SearchResponse.builder() + .totalCount(Long.valueOf(existingIndividuals.size())) + .response(existingIndividuals) + .build()); assertTrue(rowVersionValidator.validate(individualBulkRequest).isEmpty()); } @@ -78,9 +82,9 @@ void shouldGiveErrorWhenRowVersionDoesNotMatch() { .build(); individualBulkRequest.getIndividuals().get(0).setRowVersion(2); when(individualRepository.findById(anyList(), anyString(), anyBoolean())) - .thenReturn(Collections.singletonList(IndividualTestBuilder.builder() + .thenReturn(SearchResponse.builder().totalCount(1L).response(Collections.singletonList(IndividualTestBuilder.builder() .withId("some-id") - .build())); + .build())).build()); Map> errorDetailsMap = new HashMap<>(); errorDetailsMap = rowVersionValidator.validate(individualBulkRequest); List errorList = errorDetailsMap.values().stream().flatMap(Collection::stream).collect(Collectors.toList()); diff --git a/health-services/individual/src/test/java/org/egov/individual/web/controllers/IndividualApiControllerTest.java b/health-services/individual/src/test/java/org/egov/individual/web/controllers/IndividualApiControllerTest.java index d25f5270531..b9b559f6d0c 100644 --- a/health-services/individual/src/test/java/org/egov/individual/web/controllers/IndividualApiControllerTest.java +++ b/health-services/individual/src/test/java/org/egov/individual/web/controllers/IndividualApiControllerTest.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.individual.Individual; import org.egov.common.models.individual.IndividualBulkRequest; import org.egov.common.models.individual.IndividualBulkResponse; @@ -15,8 +16,8 @@ import org.egov.individual.helper.IndividualSearchRequestTestBuilder; import org.egov.individual.helper.IndividualTestBuilder; import org.egov.individual.service.IndividualService; -import org.egov.individual.web.models.IndividualSearch; -import org.egov.individual.web.models.IndividualSearchRequest; +import org.egov.common.models.individual.IndividualSearch; +import org.egov.common.models.individual.IndividualSearchRequest; import org.egov.tracer.model.ErrorRes; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -163,7 +164,7 @@ void shouldSend200OkIfSearchIsSuccessfulAndResultsAreNotEmpty() throws Exception any(String.class), any(Long.class), any(Boolean.class), - any(RequestInfo.class))).thenReturn(Collections.singletonList(responseIndividual)); + any(RequestInfo.class))).thenReturn(SearchResponse.builder().response(Collections.singletonList(responseIndividual)).build()); MvcResult result = mockMvc.perform(post("/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") .contentType(MediaType diff --git a/health-services/libraries/docker-compose.yml b/health-services/libraries/docker-compose.yml deleted file mode 100644 index fea4de2e4ca..00000000000 --- a/health-services/libraries/docker-compose.yml +++ /dev/null @@ -1,67 +0,0 @@ -version: '2' -services: - zookeeper: - image: 'confluentinc/cp-zookeeper:latest' - container_name: zookeeper - environment: - ZOOKEEPER_CLIENT_PORT: 2181 - ZOOKEEPER_TICK_TIME: 2000 - ports: - - '2181:2181' - kafka: - image: 'confluentinc/cp-kafka:latest' - container_name: kafka - depends_on: - - zookeeper - ports: - - '9092:9092' - environment: - KAFKA_BROKER_ID: 1 - KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 - KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://127.0.0.1:9092 - KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT - KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT - KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 - schema-registry: - image: confluentinc/cp-schema-registry:4.1.1 - hostname: schema-registry - ports: - - "38081:38081" - depends_on: - - kafka - environment: - SCHEMA_REGISTRY_KAFKASTORE_CONNECTION_URL: zookeeper:2181 - SCHEMA_REGISTRY_HOST_NAME: schema-registry - SCHEMA_REGISTRY_LISTENERS: http://schema-registry:38081 - SCHEMA_REGISTRY_DEBUG: "true" - - kafka-rest: - image: confluentinc/cp-kafka-rest:4.1.1 - hostname: kafka-rest - ports: - - "38082:38082" - depends_on: - - schema-registry - environment: - KAFKA_REST_ZOOKEEPER_CONNECT: zookeeper:2181 - KAFKA_REST_SCHEMA_REGISTRY_URL: schema-registry:38081 - KAFKA_REST_HOST_NAME: kafka-rest - KAFKA_REST_LISTENERS: http://kafka-rest:38082 - postgres: - image: postgres:10-bullseye - environment: - - POSTGRES_USER=postgres - - POSTGRES_PASSWORD=postgres - ports: - - 5432:5432 - magic: - image: digitsy/kafka-magic - ports: - - "9999:80" - environment: - KMAGIC_ALLOW_TOPIC_DELETE: "true" - KMAGIC_ALLOW_SCHEMA_DELETE: "true" - redis: - image: redis:3.2 - ports: - - 6379:6379 diff --git a/health-services/libraries/health-services-common/CHANGELOG.md b/health-services/libraries/health-services-common/CHANGELOG.md new file mode 100644 index 00000000000..fbb085523fc --- /dev/null +++ b/health-services/libraries/health-services-common/CHANGELOG.md @@ -0,0 +1,19 @@ +All notable changes to this module will be documented in this file. + +## 1.0.18 - 2024-08-09 +- Added validateClientReferenceIdsFromDB method to GenericRepository. + +## 1.0.16 - 2024-05-29 +- Introduced multiple reusable functions to streamline and simplify the codebase. +- Enhanced function modularity for better maintainability and readability. +- Integrated Core 2.9LTS +- Refactored existing code to utilize new reusable functions, reducing redundancy. +- Improved overall code structure for more efficient execution and easier future modifications. +- Changed Dockerfile, base image required for Java 17. + +## 1.0.12 +- The exception was replaced with CustomException in the service request client. + + +## 1.0.0 +- Base version diff --git a/health-services/libraries/health-services-common/Dockerfile b/health-services/libraries/health-services-common/Dockerfile index cd50dd4120d..80abf117900 100644 --- a/health-services/libraries/health-services-common/Dockerfile +++ b/health-services/libraries/health-services-common/Dockerfile @@ -1,8 +1,10 @@ -FROM egovio/alpine-maven-builder-jdk-8:1-master-NA-6036091e AS build +FROM egovio/amazoncorretto:17-alpine3.19 AS build ARG WORK_DIR ARG nexusUsername ARG nexusPassword WORKDIR /app +# Install Maven +RUN apk add --no-cache maven # copy the project files COPY ${WORK_DIR}/pom.xml ./pom.xml COPY ${WORK_DIR}/settings.xml ./settings.xml diff --git a/health-services/libraries/health-services-common/pom.xml b/health-services/libraries/health-services-common/pom.xml index f3afea7a2a6..8f5e0d4fae9 100644 --- a/health-services/libraries/health-services-common/pom.xml +++ b/health-services/libraries/health-services-common/pom.xml @@ -8,19 +8,20 @@ health-services-common jar health-services-common - 1.0.11-SNAPSHOT + 1.0.18-SNAPSHOT Shared classes among services org.springframework.boot spring-boot-starter-parent - 2.2.6.RELEASE + 3.2.2 - 8 - 8 + 17 + ${java.version} + ${java.version} UTF-8 @@ -52,26 +53,34 @@ spring-boot-starter-test test + + junit + junit + 4.13.2 + test + com.h2database h2 [2.1.212,) test + + jakarta.validation + jakarta.validation-api + 3.0.2 + compile + org.projectlombok lombok true + 1.18.22 com.fasterxml.jackson.datatype jackson-datatype-jsr310 - - org.projectlombok - lombok - true - org.springframework.boot spring-boot-starter-jdbc @@ -84,7 +93,7 @@ org.egov.services tracer - 2.1.4-SNAPSHOT + 2.9.0-SNAPSHOT org.springframework.boot @@ -100,6 +109,20 @@ redis.clients jedis + + + + + + org.hibernate.validator + hibernate-validator + + + org.egov.common + health-services-models + 1.0.20-SNAPSHOT + compile + @@ -107,6 +130,17 @@ org.apache.maven.plugins maven-site-plugin 3.7.1 + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.1.2 + + --add-opens java.base/java.util=ALL-UNNAMED + org.apache.maven.plugins diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/AddressDummyTest.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/AddressDummyTest.java deleted file mode 100644 index e16fec2687b..00000000000 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/AddressDummyTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.egov.common; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class AddressDummyTest { - - @JsonProperty("addressId") - private String addressId; - - @JsonProperty("addressText") - private String addressText; -} diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/mapper/GenericRowMapper.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/mapper/GenericRowMapper.java deleted file mode 100644 index 0d834d127e2..00000000000 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/mapper/GenericRowMapper.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.egov.common.data.mapper; - -import org.egov.common.utils.ObjectUtils; -import org.springframework.beans.BeanUtils; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.jdbc.support.JdbcUtils; - -import java.lang.reflect.Field; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.Map; - -/** - * GenericRowMapper is an implementation of RowMapper. It is used for mapping ResultSet from sql query to List

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

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

- *

- *

- * Requirements to use GenericRowMapper

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

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

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

- *

- *

- * Example:

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

- * class Emp{

- * private int id;

- * private int someId;

- * private String name;

- * int salary;

- * }

- *

- *

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

- *

- *

- * Usage:

- * List emps = jdbcQueryTemplate.query("select * from Employee", new GenericRowMapper(Emp.class)) - */ - - -public class GenericRowMapper implements RowMapper { - private Class mappedClass; - - public GenericRowMapper(Class mappedClass) { - this.mappedClass = mappedClass; - } - - private Object mapRow(Class clazz, Map row) throws IllegalAccessException, IllegalArgumentException { - Object parentObject = BeanUtils.instantiateClass(clazz); - Field[] fields = parentObject.getClass().getDeclaredFields(); - for (Field f : fields) { - f.setAccessible(true); - if (!f.getType().isPrimitive() && !ObjectUtils.isWrapper(f)) { - Object nestedObject = mapRow(f.getType(), row); - f.set(parentObject, nestedObject); - }else{ - Object value = row.get(f.getName()); - f.set(parentObject, value); - } - } - return parentObject; - } - - private Map getMap(ResultSet rs) throws SQLException, ClassNotFoundException { - ResultSetMetaData metaData = rs.getMetaData(); - int columnCount = metaData.getColumnCount(); - - Map row = new HashMap(columnCount); - - for (int index = 1; index <= columnCount; index++) { - String column = JdbcUtils.lookupColumnName(metaData, index); - Object value = JdbcUtils.getResultSetValue(rs, index, Class.forName(metaData.getColumnClassName(index))); - row.put(column, value); - } - return row; - } - - @Override - public T mapRow(ResultSet rs, int rowNum) throws SQLException{ - T instance; - try { - Map row = getMap(rs); - instance = (T) mapRow(this.mappedClass, row); - } catch (SQLException e) { - throw e; - } catch (Exception e){ - throw new RuntimeException(e.getMessage()); - } - - return instance; - } -} diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/Exclude.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/Exclude.java index b7df66c8ccd..e5c3d79b7a2 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/Exclude.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/Exclude.java @@ -7,5 +7,7 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) +// This annotation is used to mark fields in a model class that should be ignored or excluded when the class is being processed, +// specifically during serialization to JSON or when constructing database queries. public @interface Exclude { } diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/Table.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/Table.java index 61dbd2d5d53..5f23e34e17a 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/Table.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/Table.java @@ -7,6 +7,9 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) +// It is used to specify the table name associated with a class. +// When you annotate a class with @Table, it indicates that the class is mapped to a table in the database. +// Used in GenericQueryBuilder public @interface Table { String name() default ""; } diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/UpdateBy.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/UpdateBy.java index e1ae3c7dfc7..9a7c9869bde 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/UpdateBy.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/UpdateBy.java @@ -7,5 +7,7 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) +// This annotation is used to mark specific fields in a class that should be specially considered during update operations +// Used in GenericQueryBuilder public @interface UpdateBy { } diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/GenericQueryBuilder.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/GenericQueryBuilder.java index b6086351e9d..c223723f443 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/GenericQueryBuilder.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/GenericQueryBuilder.java @@ -4,6 +4,8 @@ import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.utils.ObjectUtils; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.time.LocalDate; import java.util.ArrayList; @@ -28,18 +30,38 @@ static String updateQueryTemplate(String tableName){ return String.format("UPDATE %s", tableName); } - static String generateClause(String clauseName, String seperator, List queryParameters){ + /** + * Generates a clause for a SQL query. + * + * @param clauseName the name of the clause (e.g., "WHERE", "AND", "OR") + * @param separator the separator between query parameters (e.g., "=", "LIKE") + * @param queryParameters the list of query parameters to be included in the clause + * @return the generated clause as a string + */ + static String generateClause(String clauseName, String separator, List queryParameters) { + // Initialize a StringBuilder to construct the clause StringBuilder clauseBuilder = new StringBuilder(); + + // If there are no query parameters, return an empty string if (queryParameters.isEmpty()) { - return " WHERE 1=1 "; + return ""; } + + // Append the clause name to the clauseBuilder clauseBuilder.append(String.format(" %s ", clauseName)); + + // Append the first query parameter to the clauseBuilder clauseBuilder.append(String.format(queryParameters.get(0))); + + // Append the remaining query parameters to the clauseBuilder with the specified separator IntStream.range(1, queryParameters.size()).forEach(i -> - clauseBuilder.append(String.format(" %s %s", seperator ,queryParameters.get(i)))); + clauseBuilder.append(String.format(" %s %s", separator, queryParameters.get(i)))); + + // Convert the clauseBuilder to a string and return it return clauseBuilder.toString(); } + static StringBuilder generateQuery(String queryTemplate, List setClauseFields, List whereClauseFields){ StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(queryTemplate); @@ -55,41 +77,93 @@ static StringBuilder generateQuery(String queryTemplate, List whereClaus return stringBuilder; } + /** + * Retrieves fields of an object based on a condition and constructs where clauses for a query. + * + * @param object the object for which fields are to be retrieved + * @param checkCondition the condition to check for each field + * @param paramsMap a map to store parameter values for the query + * @return a list of where clauses based on the fields and condition + */ static List getFieldsWithCondition(Object object, QueryFieldChecker checkCondition, Map paramsMap) { + // List to store where clauses List whereClauses = new ArrayList<>(); - Arrays.stream(object.getClass().getDeclaredFields()).forEach(field -> { - if (field.getType().equals(LocalDate.class) || field.getType().isEnum()) { - // do nothing + + // Iterate through all declared fields of the object + getAllDeclaredFields(object.getClass()).forEach(field -> { + // Check if the field is of type LocalDate or enum + if (field.getType().equals(LocalDate.class) || field.getType().isEnum() || Modifier.isStatic(field.getModifiers())) { + // Skip processing for LocalDate and enum fields + // No condition applied } else { - field.setAccessible(true); try { + // Make the field accessible for manipulation FIXME TODO + field.setAccessible(true); + } catch (Exception exception) { + return; + } + + try { + // Check if the field meets the condition and is not annotated with exclude if (!field.getType().isPrimitive() && checkCondition.check(field, object) && QueryFieldChecker.isNotAnnotatedWithExclude.check(field, object)) { + // If the field is a wrapper object if (ObjectUtils.isWrapper(field)) { + // Retrieve field name String fieldName = field.getName(); + // Add parameter to paramsMap paramsMap.put(fieldName, field.get(object)); + // Add where clause to list whereClauses.add(String.format("%s=:%s", fieldName, fieldName)); - } else if (field.getType().isAssignableFrom(ArrayList.class) + } + // If the field is an ArrayList of Strings + else if (field.getType().isAssignableFrom(ArrayList.class) && field.getGenericType() instanceof ParameterizedType && ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0].equals(String.class)) { + // Cast field value to ArrayList ArrayList arrayList = (ArrayList) field.get(object); + // Retrieve field name String fieldName = field.getName(); + // Check if the ArrayList is not null or empty if (arrayList != null && !arrayList.isEmpty()) { + // Add IN clause to list whereClauses.add(String.format("%s IN (:%s)", fieldName, fieldName)); + // Add parameter to paramsMap paramsMap.put(fieldName, arrayList); } } else { + // If the field is not a wrapper object or ArrayList, recursively process nested objects Object objectAtField = field.get(object); if (objectAtField != null) { + // Recursively call the method to retrieve fields from nested object whereClauses.addAll(getFieldsWithCondition(objectAtField, checkCondition, paramsMap)); } } } } catch (IllegalAccessException e) { + // Throw a runtime exception if there's an issue accessing the field throw new RuntimeException(e); } } }); return whereClauses; } + + + /** + * This method retrieves all declared fields from the given class and its superclasses. + * + * @param clazz the class whose fields are to be retrieved + * @return a list of all declared fields in the class and its superclasses, excluding Object class fields + */ + static List getAllDeclaredFields(Class clazz) { + List fields = new ArrayList<>(); + while (clazz != null && clazz != Object.class) { + for (Field field : clazz.getDeclaredFields()) { + fields.add(field); + } + clazz = clazz.getSuperclass(); + } + return fields; + } } diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/QueryFieldChecker.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/QueryFieldChecker.java index f31e1012a89..7ab1661349b 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/QueryFieldChecker.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/QueryFieldChecker.java @@ -1,7 +1,7 @@ package org.egov.common.data.query.builder; -import org.egov.common.data.query.annotations.Exclude; import org.egov.common.data.query.annotations.UpdateBy; +import org.egov.common.models.core.Exclude; import java.lang.reflect.Field; import java.util.Optional; @@ -12,5 +12,6 @@ public interface QueryFieldChecker { QueryFieldChecker isNotNull = (field, object) -> Optional.ofNullable(field.get(object)).isPresent(); QueryFieldChecker isAnnotatedWithUpdateBy = (field, object) -> field.getDeclaredAnnotation(UpdateBy.class) != null; + // Exclude annotation is now referred from health-services-models QueryFieldChecker isNotAnnotatedWithExclude = ((field, object) -> field.getDeclaredAnnotation(Exclude.class) == null); } diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/SelectQueryBuilder.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/SelectQueryBuilder.java index de274691e6e..3db008197d4 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/SelectQueryBuilder.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/SelectQueryBuilder.java @@ -1,5 +1,6 @@ package org.egov.common.data.query.builder; +import org.apache.commons.lang3.StringUtils; import org.egov.common.data.query.exception.QueryBuilderException; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @@ -20,9 +21,19 @@ public Map getParamsMap(){ @Override public String build(Object object) throws QueryBuilderException { + String tableName = null; + try { + tableName = GenericQueryBuilder.getTableName(object.getClass()); + } catch (Exception exception) { + throw new QueryBuilderException(exception.getMessage()); + } + + return build(object, tableName); + } + + public String build(Object object, String tableName) throws QueryBuilderException { StringBuilder queryStringBuilder = null; try { - String tableName = GenericQueryBuilder.getTableName(object.getClass()); List whereClauses = GenericQueryBuilder.getFieldsWithCondition(object, QueryFieldChecker.isNotNull, paramsMap); queryStringBuilder = GenericQueryBuilder.generateQuery(GenericQueryBuilder.selectQueryTemplate(tableName), whereClauses); } catch (Exception exception) { diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java index 347fc4966a4..537a82400cc 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java @@ -1,6 +1,7 @@ package org.egov.common.data.repository; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.producer.Producer; @@ -26,6 +27,11 @@ import static org.egov.common.utils.CommonUtils.getMethod; import static org.egov.common.utils.CommonUtils.getObjClass; +/** + * Generic Repository Class for common data operations. + * + * @param The type of entity this repository deals with. + */ @Slf4j public abstract class GenericRepository { @@ -56,10 +62,23 @@ protected GenericRepository(Producer producer, NamedParameterJdbcTemplate namedP tableName.ifPresent(tb -> this.tableName = tb); } + /** + * Finds entities by their IDs. + * + * @param ids The list of IDs to search for. + * @return A list of entities found by the given IDs. + */ public List findById(List ids) { return findById(ids, false); } + /** + * Finds entities by their IDs with an option to include deleted entities. + * + * @param ids The list of IDs to search for. + * @param includeDeleted Flag to include deleted entities in the search result. + * @return A list of entities found by the given IDs. + */ protected List findInCache(List ids) { ArrayList objFound = new ArrayList<>(); Collection collection = ids.stream().filter(Objects::nonNull) @@ -81,19 +100,38 @@ protected List findInCache(List ids) { return objFound; } + /** + * Finds entities by their IDs with an option to include deleted entities, + * using the default column name "id" for ID search. + * + * @param ids The list of IDs to search for. + * @param includeDeleted Flag to include deleted entities in the search result. + * @return A list of entities found by the given IDs. + */ public List findById(List ids, Boolean includeDeleted) { + // Delegates to the main findById method with the default column name "id" return findById(ids, includeDeleted, "id"); } + /** + * Finds entities by their IDs with options to include deleted entities and specify a column name. + * + * @param ids The list of IDs to search for. + * @param includeDeleted Flag to include deleted entities in the search result. + * @param columnName The name of the column to search IDs in. + * @return A list of entities found by the given IDs. + */ public List findById(List ids, Boolean includeDeleted, String columnName) { List objFound = findInCache(ids); if (!objFound.isEmpty()) { Method idMethod = getIdMethod(objFound, columnName); Method isDeleted = getMethod("getIsDeleted", getObjClass(objFound)); - objFound = objFound.stream() - .filter(entity -> Objects.equals(ReflectionUtils.invokeMethod(isDeleted, entity), includeDeleted)) - .collect(Collectors.toList()); + if (!includeDeleted) { + objFound = objFound.stream() + .filter(entity -> Objects.equals(ReflectionUtils.invokeMethod(isDeleted, entity), false)) + .collect(Collectors.toList()); + } ids.removeAll(objFound.stream() .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) .collect(Collectors.toList())); @@ -115,6 +153,13 @@ public List findById(List ids, Boolean includeDeleted, String columnN return objFound; } + /** + * Saves entities to Kafka and caches them. + * + * @param objects The list of entities to save. + * @param topic The Kafka topic to push the entities to. + * @return The list of saved entities. + */ public List save(List objects, String topic) { producer.push(topic, objects); log.info("Pushed to kafka"); @@ -123,6 +168,14 @@ public List save(List objects, String topic) { return objects; } + /** + * Saves entities to Kafka, caches them with specified cache key. + * + * @param objects The list of entities to save. + * @param topic The Kafka topic to push the entities to. + * @param cacheKey The cache key to use for caching the entities. + * @return The list of saved entities. + */ public List save(List objects, String topic, String cacheKey) { producer.push(topic, objects); log.info("Pushed to kafka"); @@ -131,6 +184,7 @@ public List save(List objects, String topic, String cacheKey) { return objects; } + // Cache objects by key protected void cacheByKey(List objects, String fieldName) { try{ Method getIdMethod = getIdMethod(objects, fieldName); @@ -150,10 +204,15 @@ protected void cacheByKey(List objects, String fieldName) { redisTemplate.expire(tableName, Long.parseLong(timeToLive), TimeUnit.SECONDS); } } catch (Exception exception) { - log.warn("Error while saving to cache: {}", exception.getMessage()); + log.warn("Error while saving to cache: {}", ExceptionUtils.getStackTrace(exception)); } } + /** + * Puts objects in cache. + * + * @param objects The list of objects to put in cache. + */ public void putInCache(List objects) { if(objects == null || objects.isEmpty()) { return; @@ -163,6 +222,12 @@ public void putInCache(List objects) { // cacheByKey(objects, "id"); } + /** + * Puts objects in cache with specified cache key. + * + * @param objects The list of objects to put in cache. + * @param key The cache key to use for caching the objects. + */ public void putInCache(List objects, String key) { if(objects == null || objects.isEmpty()) { return; @@ -171,13 +236,25 @@ public void putInCache(List objects, String key) { cacheByKey(objects, key); } + /** + * Finds entities based on search criteria. + * + * @param searchObject The object containing search criteria. + * @param limit The maximum number of entities to return. + * @param offset The offset for pagination. + * @param tenantId The tenant ID to filter entities. + * @param lastChangedSince The timestamp for last modified entities. + * @param includeDeleted Flag to include deleted entities in the search result. + * @return A list of entities found based on the search criteria. + * @throws QueryBuilderException If an error occurs while building the query. + */ public List find(Object searchObject, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws QueryBuilderException { - String query = selectQueryBuilder.build(searchObject); + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws QueryBuilderException { + String query = selectQueryBuilder.build(searchObject, tableName); query += " AND tenantId=:tenantId "; if (query.contains(tableName + " AND")) { query = query.replace(tableName + " AND", tableName + " WHERE"); @@ -198,6 +275,13 @@ public List find(Object searchObject, return namedParameterJdbcTemplate.query(query, paramsMap, rowMapper); } + /** + * Validates IDs against existing entities. + * + * @param idsToValidate The list of IDs to validate. + * @param columnName The name of the column containing IDs. + * @return A list of valid IDs. + */ public List validateIds(List idsToValidate, String columnName){ List validIds = findById(idsToValidate, false, columnName); if (validIds.isEmpty()) { @@ -207,4 +291,23 @@ public List validateIds(List idsToValidate, String columnName){ return validIds.stream().map((obj) -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) .collect(Collectors.toList()); } + + public List validateClientReferenceIdsFromDB(List clientReferenceIds, Boolean isDeletedKeyPresent) { + List objFound = new ArrayList<>(); + + String query = null; + + if(isDeletedKeyPresent) { + query = String.format("SELECT clientReferenceId FROM %s WHERE clientReferenceId IN (:ids) AND isDeleted = false", tableName); + } else { + query = String.format("SELECT clientReferenceId FROM %s WHERE clientReferenceId IN (:ids) ", tableName); + } + + Map paramMap = new HashMap<>(); + paramMap.put("ids", clientReferenceIds); + + objFound.addAll(namedParameterJdbcTemplate.queryForList(query, paramMap, String.class)); + + return objFound; + } } diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/error/handler/ErrorHandler.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/error/handler/ErrorHandler.java index ec82e2065c1..ffd00e62a76 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/error/handler/ErrorHandler.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/error/handler/ErrorHandler.java @@ -4,7 +4,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; @Component public class ErrorHandler { diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/http/client/ServiceRequestClient.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/http/client/ServiceRequestClient.java index b41df36a4af..6a4fcab2409 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/http/client/ServiceRequestClient.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/http/client/ServiceRequestClient.java @@ -1,6 +1,5 @@ package org.egov.common.http.client; - import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import lombok.extern.slf4j.Slf4j; @@ -11,6 +10,10 @@ import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; +/** + * Client for making service requests via HTTP. + * This class provides methods to fetch results from a service using HTTP POST requests. + */ @Repository @Slf4j public class ServiceRequestClient { @@ -19,24 +22,39 @@ public class ServiceRequestClient { private final RestTemplate restTemplate; - + // Constructor injection of ObjectMapper and RestTemplate @Autowired public ServiceRequestClient(@Qualifier("objectMapper") ObjectMapper objectMapper, RestTemplate restTemplate) { this.objectMapper = objectMapper; this.restTemplate = restTemplate; } - - public T fetchResult(StringBuilder uri, Object request, Class - clazz) throws Exception { + /** + * Fetches result from a service using HTTP POST. + * + * @param uri The URI to send the request to. + * @param request The request object to send. + * @param clazz The class of the response object. + * @param The type of the response object. + * @return The response object received from the service. + * @throws CustomException If an error occurs during the service request. + */ + public T fetchResult(StringBuilder uri, Object request, Class clazz) { + // Configure the ObjectMapper to ignore empty beans during serialization objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); T response; try { + // Perform HTTP POST request and receive the response response = restTemplate.postForObject(uri.toString(), request, clazz); } catch (HttpClientErrorException e) { + // Handle HTTP client errors throw new CustomException("HTTP_CLIENT_ERROR", String.format("%s - %s", e.getMessage(), e.getResponseBodyAsString())); + } catch (Exception exception) { + // Handle other exceptions + throw new CustomException("SERVICE_REQUEST_CLIENT_ERROR", + exception.getMessage()); } return response; } -} \ No newline at end of file +} diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/CreateUserRequest.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/CreateUserRequest.java index db4196aec11..ebcc79c9259 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/CreateUserRequest.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/CreateUserRequest.java @@ -5,8 +5,8 @@ import lombok.NoArgsConstructor; import org.egov.common.contract.request.RequestInfo; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; @AllArgsConstructor @Getter diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/User.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/User.java index 95a8618aab2..46e1495f5d1 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/User.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/User.java @@ -10,8 +10,8 @@ import org.hibernate.validator.constraints.Email; import org.springframework.util.CollectionUtils; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.Collections; import java.util.Date; diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/UserRequest.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/UserRequest.java index e194df585e2..75aa1bfb17d 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/UserRequest.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/UserRequest.java @@ -1,7 +1,14 @@ package org.egov.common.models.user; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -9,14 +16,6 @@ import lombok.Setter; import lombok.ToString; import org.hibernate.validator.constraints.Email; -import org.hibernate.validator.constraints.SafeHtml; - -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; -import java.util.Date; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; @Setter @Getter @@ -25,14 +24,19 @@ @AllArgsConstructor @ToString public class UserRequest { +/** + * FIXME + * to be removed or replace with some alternative as the //@SafeHtml is no longer present + * with modern version of hibernate validator supported by springboot version 3.2.2 + */ private Long id; - @SafeHtml +// //@SafeHtml @Size(max = 64) private String userName; - @SafeHtml +// //@SafeHtml @Size(max = 5) private String salutation; @@ -54,33 +58,33 @@ public class UserRequest { @Size(max = 128) private String emailId; - @SafeHtml + //@SafeHtml @Size(max = 50) private String altContactNumber; - @SafeHtml + //@SafeHtml @Size(max = 10) private String pan; - @SafeHtml + //@SafeHtml @Size(max = 20) private String aadhaarNumber; - @SafeHtml + //@SafeHtml @Size(max = 300) private String permanentAddress; - @SafeHtml + //@SafeHtml @Pattern(regexp = UserServiceConstants.PATTERN_CITY) @Size(max = 50) private String permanentCity; - @SafeHtml + //@SafeHtml @Pattern(regexp = UserServiceConstants.PATTERN_PINCODE) @Size(max = 10) private String permanentPinCode; - @SafeHtml + //@SafeHtml @Size(max = 300) private String correspondenceAddress; @@ -93,7 +97,7 @@ public class UserRequest { private String correspondencePinCode; private Boolean active; - @SafeHtml + //@SafeHtml @Size(max = 16) private String locale; @@ -106,19 +110,19 @@ public class UserRequest { private String fatherOrHusbandName; private GuardianRelation relationship; - @SafeHtml + //@SafeHtml @Size(max = 36) private String signature; - @SafeHtml + //@SafeHtml @Size(max = 32) private String bloodGroup; - @SafeHtml + //@SafeHtml @Size(max = 36) private String photo; - @SafeHtml + //@SafeHtml @Size(max = 300) private String identificationMark; private Long createdBy; @@ -126,7 +130,7 @@ public class UserRequest { @Size(max = 64) private String password; - @SafeHtml + //@SafeHtml private String otpReference; private Long lastModifiedBy; @@ -136,7 +140,7 @@ public class UserRequest { private Set roles; - @SafeHtml + //@SafeHtml @Size(max = 36) private String uuid; diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/IdGenService.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/IdGenService.java index ec6e1a814f9..c693e8f6788 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/IdGenService.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/IdGenService.java @@ -37,7 +37,7 @@ public IdGenService(ServiceRequestClient restRepo, } public List getIdList(RequestInfo requestInfo, String tenantId, String idName, - String idFormat, Integer count) throws Exception { + String idFormat, Integer count) { List reqList = new ArrayList<>(); for (int i = 0; i < count; i++) { reqList.add(IdRequest.builder().idName(idName).format(idFormat).tenantId(tenantId).build()); diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/MdmsService.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/MdmsService.java index 10208611a30..b946a6380d4 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/MdmsService.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/MdmsService.java @@ -11,7 +11,7 @@ @Slf4j @Service -@ConditionalOnExpression("!'${egov.mdms.integration.enabled}'.isEmpty() && ${egov.mdms.integration.enabled:false} && !'${egov.mdms.host}'.isEmpty() && !'${egov.mdms.master.name}'.isEmpty() && !'${egov.mdms.search.endpoint}'.isEmpty()") +@ConditionalOnExpression("!'${egov.mdms.integration.enabled}'.isEmpty() && ${egov.mdms.integration.enabled:false} && !'${egov.mdms.host}'.isEmpty() && !'${egov.mdms.search.endpoint}'.isEmpty()") public class MdmsService { private final ServiceRequestClient restRepo; diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java index e19ed5b2023..927a05044ca 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java @@ -1,23 +1,5 @@ package org.egov.common.utils; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; -import lombok.extern.slf4j.Slf4j; -import org.egov.common.contract.request.RequestInfo; -import org.egov.common.ds.Tuple; -import org.egov.common.error.handler.ErrorHandler; -import org.egov.common.models.ApiDetails; -import org.egov.common.models.Error; -import org.egov.common.models.ErrorDetails; -import org.egov.common.validator.Validator; -import org.egov.tracer.model.CustomException; -import org.egov.tracer.model.ErrorDetail; -import org.egov.tracer.model.ErrorEntity; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.util.ReflectionUtils; - import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; @@ -39,6 +21,26 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.ds.Tuple; +import org.egov.common.error.handler.ErrorHandler; +import org.egov.common.models.ApiDetails; +import org.egov.common.models.Error; +import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.URLParams; +import org.egov.common.validator.Validator; +import org.egov.tracer.model.CustomException; +import org.egov.tracer.model.ErrorDetail; +import org.egov.tracer.model.ErrorEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.util.ReflectionUtils; + import static org.egov.common.utils.ValidatorUtils.getErrorForNullId; @Slf4j @@ -56,6 +58,8 @@ private CommonUtils() { } + //TODO To be removed as it is only used by Product service which is now depricated + @Deprecated public static boolean isForUpdate(Object obj) { Method getApiOperationMethod = getMethod(GET_API_OPERATION, obj.getClass()); Object apiOperation = ReflectionUtils.invokeMethod(getApiOperationMethod, obj); @@ -66,6 +70,8 @@ public static boolean isForUpdate(Object obj) { return "UPDATE".equals(ReflectionUtils.invokeMethod(nameMethod, apiOperation)); } + //TODO To be removed as it is only used by Product service which is now depricated + @Deprecated public static boolean isForDelete(Object obj) { Method getApiOperationMethod = getMethod(GET_API_OPERATION, obj.getClass()); Object apiOperation = ReflectionUtils.invokeMethod(getApiOperationMethod, obj); @@ -76,6 +82,8 @@ public static boolean isForDelete(Object obj) { return "DELETE".equals(ReflectionUtils.invokeMethod(nameMethod, apiOperation)); } + //TODO To be removed as it is only used by Product service which is now depricated + @Deprecated public static boolean isForCreate(Object obj) { Method getApiOperationMethod = getMethod(GET_API_OPERATION, obj.getClass()); Object apiOperation = ReflectionUtils.invokeMethod(getApiOperationMethod, obj); @@ -102,6 +110,8 @@ public static List getDifference(List list, List subList) { return newList; } + //TODO To be removed as it is only used by Product service which is now depricated + @Deprecated public static void validateIds(Set idsToValidate, UnaryOperator> validator) { List idsToValidateList = new ArrayList<>(idsToValidate); List validIds = validator.apply(idsToValidateList); @@ -112,6 +122,13 @@ public static void validateIds(Set idsToValidate, UnaryOperator> } } + /** + * Retrieves audit details for creating an entity. + * This method generates audit details including creation and last modified timestamps. + * + * @param requestInfo The request information containing user details. + * @return The audit details for create operation. + */ public static AuditDetails getAuditDetailsForCreate(RequestInfo requestInfo) { log.info("Creating audit details for create api"); Long time = System.currentTimeMillis(); @@ -119,7 +136,8 @@ public static AuditDetails getAuditDetailsForCreate(RequestInfo requestInfo) { .createdBy(requestInfo.getUserInfo().getUuid()) .createdTime(time) .lastModifiedBy(requestInfo.getUserInfo().getUuid()) - .lastModifiedTime(time).build(); + .lastModifiedTime(time) + .build(); } /** @@ -142,39 +160,111 @@ public static AuditDetails getAuditDetailsForUpdate(AuditDetails existingAuditDe } } + /** + * Checks if the search is performed by ID only. + * @param obj The object to check. + * @return True if the search is by ID only, false otherwise. + */ public static boolean isSearchByIdOnly(Object obj) { return isSearchByIdOnly(obj, "id"); } + /** + * Checks if the search is performed only by the specified field. + * + * @param obj The object to perform the search on. + * @param fieldName The name of the field to search. + * @return true if the search is performed only by the specified field, otherwise false. + */ public static boolean isSearchByIdOnly(Object obj, String fieldName) { + // Get the class of the object Class objClass = obj.getClass(); + // Capitalize the first letter of the field name String propertyName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); - Method setIdMethod = getMethod("set"+propertyName, objClass); - Method getIdMethod = getMethod("get"+propertyName, objClass); + // Get the method to set the field + Method setFieldMethod = getMethod("set" + propertyName, objClass); + // Get the method to get the field value + Method getFieldMethod = getMethod("get" + propertyName, objClass); + // Create a new instance of the object Object finalObject = null; try { finalObject = objClass.newInstance(); } catch (InstantiationException | IllegalAccessException e) { + // Throw a runtime exception if instantiation fails throw new RuntimeException(e); } - Object id = ReflectionUtils.invokeMethod(getIdMethod, obj); - ReflectionUtils.invokeMethod(setIdMethod, finalObject, id); + // Get the ID of the object + Object id = ReflectionUtils.invokeMethod(getFieldMethod, obj); + // If ID is null, return false if (id == null) { return false; } - String actual = obj.toString(); - String expected = finalObject.toString(); - return actual.equals(expected); + // Set the ID to the final object + ReflectionUtils.invokeMethod(setFieldMethod, finalObject, id); + + // If the object is an instance of URLParams, set common properties + if (obj instanceof URLParams) { + URLParams urlParamsObj = ((URLParams) obj); + URLParams finalUrlParamsObj = ((URLParams) finalObject); + finalUrlParamsObj.setIncludeDeleted(urlParamsObj.getIncludeDeleted()); + finalUrlParamsObj.setTenantId(urlParamsObj.getTenantId()); + finalUrlParamsObj.setOffset(urlParamsObj.getOffset()); + finalUrlParamsObj.setLimit(urlParamsObj.getLimit()); + finalUrlParamsObj.setLastChangedSince(urlParamsObj.getLastChangedSince()); + } + + // compare both objects + return areObjectsEqual(obj, finalObject); } + public static boolean areObjectsEqual(Object obj1, Object obj2) { + if (obj1 == null || obj2 == null) { + return false; + } + + // Get the class of the objects + Class objClass = obj1.getClass(); + + // Iterate through all fields in the class, including parent fields + StringBuilder obj1Fields = new StringBuilder(); + StringBuilder obj2Fields = new StringBuilder(); + + while(objClass.getSuperclass() != null) { + for (Field field : objClass.getDeclaredFields()) { + field.setAccessible(true); // Ensure private fields are accessible + + try { + // Get the value of the field for each object + Object value1 = field.get(obj1); + Object value2 = field.get(obj2); + + // Append the field name and value to the string representation + obj1Fields.append(field.getName()).append(":").append(value1).append(","); + obj2Fields.append(field.getName()).append(":").append(value2).append(","); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + objClass = objClass.getSuperclass(); + } + + // Compare the string representations of the objects + return obj1Fields.toString().equals(obj2Fields.toString()); + } + + + //TODO To be removed as it is only used by Product service which is now depricated + @Deprecated public static void checkRowVersion(Map idToObjMap, List objList) { Class objClass = getObjClass(objList); checkRowVersion(idToObjMap, objList, getMethod("getId", objClass)); } + //TODO To be removed as it is only used by Product service which is now depricated + @Deprecated public static void checkRowVersion(Map idToObjMap, List objList, Method idMethod) { Class objClass = getObjClass(objList); Method rowVersionMethod = getMethod("getRowVersion", objClass); @@ -189,10 +279,21 @@ public static void checkRowVersion(Map idToObjMap, List objLis } } + /** + * Retrieves entities from a list with mismatched row versions compared to a map of IDs to objects. + * @param idToObjMap A map of IDs to objects. + * @param objList The list of objects to check. + * @param idMethod The method to retrieve the ID of an object. + * @param The type of objects in the list. + * @return A list of entities with mismatched row versions. + */ public static List getEntitiesWithMismatchedRowVersion(Map idToObjMap, List objList, Method idMethod) { + // Get the class of objects in the list Class objClass = getObjClass(objList); + // Get the method to retrieve the row version Method rowVersionMethod = getMethod("getRowVersion", objClass); + // Filter the object list to include only those with mismatched row versions return objList.stream() .filter(obj -> !Objects.equals(ReflectionUtils.invokeMethod(rowVersionMethod, obj), ReflectionUtils.invokeMethod(rowVersionMethod, @@ -201,10 +302,20 @@ public static List getEntitiesWithMismatchedRowVersion(Map idT .collect(Collectors.toList()); } + /** + * Retrieves the tenant ID from a list of objects. + * @param objList The list of objects from which to retrieve the tenant ID. + * @param The type of objects in the list. + * @return The tenant ID. + */ public static String getTenantId(List objList) { + // Retrieve any object from the list Object obj = objList.stream().findAny().get(); + // Get the method to retrieve the tenant ID Method getTenantIdMethod = getMethod("getTenantId", obj.getClass()); + // Invoke the method to retrieve the tenant ID String tenantId = (String) ReflectionUtils.invokeMethod(getTenantIdMethod, obj); + // Log the retrieved tenant ID log.info("tenantId is {}", tenantId); return tenantId; } @@ -236,6 +347,7 @@ public static void enrichForCreate(List objList, List idList, Req * @param updateRowVersion denoting whether to update rowVersion or not * @param is any type that has an id field, auditDetails field, rowVersion field and isDeleted field with setters and getters */ + //TODO COMPARE the size and throw error when objList and idList are not equal public static void enrichForCreate(List objList, List idList, RequestInfo requestInfo, boolean updateRowVersion) { AuditDetails auditDetails = getAuditDetailsForCreate(requestInfo); @@ -256,149 +368,279 @@ public static void enrichForCreate(List objList, List idList, Req }); } + /** + * Retrieves the ID method from a list of objects, prioritizing "id" and "clientReferenceId" fields. + * @param objList The list of objects from which to retrieve the ID method. + * @param The type of objects in the list. + * @return The ID method. + */ public static Method getIdMethod(List objList) { return getIdMethod(objList, "id", "clientReferenceId"); } + /** + * Retrieves the ID method from a list of objects based on a specified ID field name. + * @param objList The list of objects from which to retrieve the ID method. + * @param idFieldName The name of the ID field. + * @param The type of objects in the list. + * @return The ID method. + */ public static Method getIdMethod(List objList, String idFieldName) { - String idMethodName = "get" + idFieldName.substring(0, 1).toUpperCase() - + idFieldName.substring(1); + // Construct the method name based on the ID field name + String idMethodName = "get" + idFieldName.substring(0, 1).toUpperCase() + idFieldName.substring(1); + // Get the ID method using the constructed method name return getMethod(idMethodName, getObjClass(objList)); } + /** + * Retrieves the ID method from a list of objects based on specified ID and client reference ID field names. + * @param objList The list of objects from which to retrieve the ID method. + * @param idField The name of the ID field. + * @param clientReferenceIdField The name of the client reference ID field. + * @param The type of objects in the list. + * @return The ID method. + */ public static Method getIdMethod(List objList, String idField, String clientReferenceIdField) { - String idMethodName = "get" + idField.substring(0, 1).toUpperCase() - + idField.substring(1); - String clientReferenceIdMethodName = "get" + clientReferenceIdField.substring(0, 1).toUpperCase() - + clientReferenceIdField.substring(1); - try{ + // Construct the method names based on the specified field names + String idMethodName = "get" + idField.substring(0, 1).toUpperCase() + idField.substring(1); + String clientReferenceIdMethodName = "get" + clientReferenceIdField.substring(0, 1).toUpperCase() + clientReferenceIdField.substring(1); + try { + // Attempt to retrieve the ID method Method getId = getMethod(idMethodName, getObjClass(objList)); + // Invoke the ID method on an object from the list to check if it returns a non-null value Object value = ReflectionUtils.invokeMethod(getId, objList.stream().findAny().get()); + // If the value is not null, return the ID method if (value != null) { return getId; } - } catch (CustomException e){ + } catch (CustomException e) { + // Log and handle any custom exceptions log.error(e.getMessage()); } - + // If the ID method does not return a non-null value, return the client reference ID method return getMethod(clientReferenceIdMethodName, getObjClass(objList)); } + + /** + * Enriches the objects in a list with IDs from a corresponding list of IDs. + * @param objList The list of objects to enrich with IDs. + * @param idList The list of IDs to use for enrichment. + * @param The type of objects in the list. + */ public static void enrichId(List objList, List idList) { + // Get the class of objects in the list Class objClass = getObjClass(objList); + // Get the method to set the ID Method setIdMethod = getMethod("setId", objClass); + // Iterate over the indices of the object list IntStream.range(0, objList.size()) .forEach(i -> { + // Get the object at the current index final Object obj = objList.get(i); + // Invoke the method to set the ID on the object using the corresponding ID from the ID list ReflectionUtils.invokeMethod(setIdMethod, obj, idList.get(i)); }); } + /** + * Enriches objects for update based on a map of IDs to objects and a request object. + * @param idToObjMap A map of IDs to objects. + * @param request The request object. + * @param The type of objects in the map. + */ public static void enrichForUpdate(Map idToObjMap, Object request) { + // Get the class of objects in the map Class objClass = getObjClass(Arrays.asList(idToObjMap.values().toArray())); + // Get the class of the request object Class requestObjClass = request.getClass(); + // Get methods related to row version, audit details, and request information Method getRowVersionMethod = getMethod("getRowVersion", objClass); Method setRowVersionMethod = getMethod("setRowVersion", objClass); Method setAuditDetailsMethod = getMethod("setAuditDetails", objClass); Method getAuditDetailsMethod = getMethod("getAuditDetails", objClass); - Method getRequestInfoMethod = getMethod("getRequestInfo", requestObjClass); + // Iterate over the keys (IDs) in the map idToObjMap.keySet().forEach(i -> { + // Get the object corresponding to the current ID Object obj = idToObjMap.get(i); + // Retrieve row version and update it Integer rowVersion = (Integer) ReflectionUtils.invokeMethod(getRowVersionMethod, obj); ReflectionUtils.invokeMethod(setRowVersionMethod, obj, rowVersion + 1); - RequestInfo requestInfo = (RequestInfo) ReflectionUtils - .invokeMethod(getRequestInfoMethod, request); + // Retrieve request information + RequestInfo requestInfo = (RequestInfo) ReflectionUtils.invokeMethod(getRequestInfoMethod, request); + // Retrieve existing audit details and update them AuditDetails existingAuditDetails = (AuditDetails) ReflectionUtils.invokeMethod(getAuditDetailsMethod, obj); AuditDetails auditDetailsForUpdate = getAuditDetailsForUpdate(existingAuditDetails, requestInfo.getUserInfo().getUuid()); ReflectionUtils.invokeMethod(setAuditDetailsMethod, obj, auditDetailsForUpdate); }); } - public static void enrichForUpdate(Map idToObjMap, List existingObjList, Object request) { - Class objClass = getObjClass(existingObjList); - enrichForUpdate(idToObjMap, existingObjList, request, getMethod("getId", objClass)); - } - + /** + * Enriches objects for update based on a map of IDs to objects, a list of existing objects, a request object, and an ID method. + * @param idToObjMap A map of IDs to objects. + * @param existingObjList The list of existing objects. + * @param request The request object. + * @param idMethod The method to retrieve the ID. + * @param The type of objects in the list. + */ public static void enrichForUpdate(Map idToObjMap, List existingObjList, Object request, Method idMethod) { + // Get the class of objects in the list Class objClass = getObjClass(existingObjList); + // Get the class of the request object Class requestObjClass = request.getClass(); + // Get methods related to deletion, row version, audit details, and request information Method setIsDeletedMethod = getMethod("setIsDeleted", objClass); Method getRowVersionMethod = getMethod("getRowVersion", objClass); Method setRowVersionMethod = getMethod("setRowVersion", objClass); Method getAuditDetailsMethod = getMethod("getAuditDetails", objClass); Method setAuditDetailsMethod = getMethod("setAuditDetails", objClass); Method getRequestInfoMethod = getMethod("getRequestInfo", requestObjClass); + // Iterate over the indices of the existing object list IntStream.range(0, existingObjList.size()).forEach(i -> { - Object obj = idToObjMap.get(ReflectionUtils.invokeMethod(idMethod, - existingObjList.get(i))); + // Get the object corresponding to the current index + Object obj = idToObjMap.get(ReflectionUtils.invokeMethod(idMethod, existingObjList.get(i))); try { + // Get the API operation method and API operation name Method getApiOperationMethod = getMethod(GET_API_OPERATION, requestObjClass); Object apiOperation = ReflectionUtils.invokeMethod(getApiOperationMethod, request); Method nameMethod = CommonUtils.getMethod("name", Enum.class); + // If the API operation is DELETE, set the object's "isDeleted" flag to true if ("DELETE".equals(ReflectionUtils.invokeMethod(nameMethod, apiOperation))) { ReflectionUtils.invokeMethod(setIsDeletedMethod, obj, true); } } catch (Exception exception) { - // Do nothing remove later + // Do nothing; remove later } - + // Retrieve row version and update it Integer rowVersion = (Integer) ReflectionUtils.invokeMethod(getRowVersionMethod, obj); ReflectionUtils.invokeMethod(setRowVersionMethod, obj, rowVersion + 1); - RequestInfo requestInfo = (RequestInfo) ReflectionUtils - .invokeMethod(getRequestInfoMethod, request); - AuditDetails existingAuditDetails = (AuditDetails) ReflectionUtils - .invokeMethod(getAuditDetailsMethod, existingObjList.get(i)); - AuditDetails auditDetailsForUpdate = getAuditDetailsForUpdate(existingAuditDetails, - requestInfo.getUserInfo().getUuid()); + // Retrieve request information + RequestInfo requestInfo = (RequestInfo) ReflectionUtils.invokeMethod(getRequestInfoMethod, request); + // Retrieve existing audit details and update them + AuditDetails existingAuditDetails = (AuditDetails) ReflectionUtils.invokeMethod(getAuditDetailsMethod, existingObjList.get(i)); + AuditDetails auditDetailsForUpdate = getAuditDetailsForUpdate(existingAuditDetails, requestInfo.getUserInfo().getUuid()); ReflectionUtils.invokeMethod(setAuditDetailsMethod, obj, auditDetailsForUpdate); }); } + /** + * Enriches objects for update based on a map of IDs to objects, a list of existing objects, and a request object. + * + * @param idToObjMap A map of IDs to objects. + * @param existingObjList The list of existing objects. + * @param request The request object. + * @param The type of objects in the list. + */ + public static void enrichForUpdate(Map idToObjMap, List existingObjList, Object request) { + Class objClass = getObjClass(existingObjList); + Method getIdMethod = getMethod("getId", objClass); + + enrichForUpdate(idToObjMap, existingObjList, request, getIdMethod); + } + + + /** + * Creates a map of IDs to objects using the default ID method. + * @param objList The list of objects from which to create the map. + * @param The type of objects in the list. + * @return A map of IDs to objects. + */ public static Map getIdToObjMap(List objList) { + // Get the class of objects in the list Class objClass = getObjClass(objList); - return getIdToObjMap(objList, getMethod("getId", objClass)); + // Get the default ID method + Method idMethod = getMethod("getId", objClass); + // Delegate to the overloaded method to create the map + return getIdToObjMap(objList, idMethod); } + /** + * Creates a map of IDs to objects using the specified ID method. + * @param objList The list of objects from which to create the map. + * @param idMethod The method to retrieve the ID from an object. + * @param The type of objects in the list. + * @return A map of IDs to objects. + */ public static Map getIdToObjMap(List objList, Method idMethod) { - return objList.stream().collect(Collectors.toMap(obj -> (String) ReflectionUtils - .invokeMethod(idMethod, obj), obj -> obj, (obj1, obj2) -> obj2)); + // Collect the objects into a map using the specified ID method + return objList.stream().collect(Collectors.toMap( + obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj), + obj -> obj, + (obj1, obj2) -> obj2 + )); } + + /** + * Validates entities by comparing the number of entities in the request map with those in the database list. + * @param idToObjInRequestMap A map of IDs to objects in the request. + * @param objInDbList The list of objects in the database. + * @param The type of objects in the lists. + */ public static void validateEntities(Map idToObjInRequestMap, List objInDbList) { + // Check if the number of entities in the request map exceeds those in the database list if (idToObjInRequestMap.size() > objInDbList.size()) { + // Get the list of IDs for objects in the database List idsForObjInDb = getIdList(objInDbList); + // Identify the IDs for invalid objects in the request map List idsForInvalidObj = idToObjInRequestMap.keySet().stream() .filter(id -> !idsForObjInDb.contains(id)) .collect(Collectors.toList()); + // Log and throw an exception for the invalid entities log.error("Invalid entities {}", idsForInvalidObj); throw new CustomException("INVALID_ENTITY", idsForInvalidObj.toString()); } } - public static void validateEntities(Map idToObjInRequestMap, List objInDbList, - Method idMethod) { + /** + * Validates entities by comparing the number of entities in the request map with those in the database list, + * using a specified ID retrieval method. + * @param idToObjInRequestMap A map of IDs to objects in the request. + * @param objInDbList The list of objects in the database. + * @param idMethod The method to retrieve the ID from an object. + * @param The type of objects in the lists. + */ + public static void validateEntities(Map idToObjInRequestMap, List objInDbList, Method idMethod) { + // Check if the number of entities in the request map exceeds those in the database list if (idToObjInRequestMap.size() > objInDbList.size()) { + // Get the list of IDs for objects in the database using the specified ID retrieval method List idsForObjInDb = getIdList(objInDbList, idMethod); + // Identify the IDs for invalid objects in the request map List idsForInvalidObj = idToObjInRequestMap.keySet().stream() .filter(id -> !idsForObjInDb.contains(id)) .collect(Collectors.toList()); + // Log and throw an exception for the invalid entities log.error("Invalid entities {}", idsForInvalidObj); throw new CustomException("INVALID_ENTITY", idsForInvalidObj.toString()); } } + + /** + * Checks for non-existent entities in the request map based on the ID method, comparing them with entities in the database list. + * @param idToObjInRequestMap A map of IDs to objects in the request. + * @param objInDbList The list of objects in the database. + * @param idMethod The method to retrieve the ID from an object. + * @param The type of objects in the lists. + * @return A list of entities from the request map that do not exist in the database. + */ public static List checkNonExistentEntities(Map idToObjInRequestMap, List objInDbList, Method idMethod) { + // Check if the number of entities in the request map exceeds those in the database list if (idToObjInRequestMap.size() > objInDbList.size()) { + // Get the list of IDs for objects in the database using the specified ID retrieval method List idsForObjInDb = getIdList(objInDbList, idMethod); + // Filter out entities from the request map that do not exist in the database list return idToObjInRequestMap.entrySet().stream() - .filter(e -> !idsForObjInDb.contains(e.getKey())).map(Map.Entry::getValue) - .collect(Collectors.toList()); + .filter(e -> !idsForObjInDb.contains(e.getKey())) // Filter non-existent entities + .map(Map.Entry::getValue) // Map to the corresponding object + .collect(Collectors.toList()); // Collect into a list } - return Collections.emptyList(); + return Collections.emptyList(); // Return an empty list if no non-existent entities are found } + public static List getIdList(List objList) { if (objList == null || objList.isEmpty()) { return Collections.emptyList(); @@ -500,24 +742,41 @@ public static List collectFromList(List objList, Function clazz, String fieldName) { + Class parentClass = clazz; + while (parentClass != null) { + try { + return parentClass.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + // Field not found in this class, proceed to the parent class + parentClass = parentClass.getSuperclass(); + } + } + // Field not found in the class hierarchy + return null; + } + public static String getIdFieldName(Method method) { if (method != null) { return method.getName().contains("Reference") ? "clientReferenceId" : "id"; @@ -800,7 +1059,9 @@ public static void handleErrors(Map errorDetailsMap, boolea if (isBulk) { ErrorHandler.exceptionAdviseInstance.exceptionHandler(errorDetailList); } else { - throw new CustomException(getErrorMap(errorDetailList)); + Map getErrorMap = getErrorMap(errorDetailList); + String code = getErrorMap.keySet().stream().collect(Collectors.joining(":")); + throw new CustomException(code, errorDetailsMap.values().toString()); } } } @@ -860,16 +1121,16 @@ public static void populateErrorDetails(T payload, Error error, } private static Method findMethod(String methodName, Class clazz) { - return Arrays.stream(ReflectionUtils.getDeclaredMethods(clazz)) + return Arrays.stream(ReflectionUtils.getAllDeclaredMethods(clazz)) .filter(m -> m.getName().equals(methodName)) .findFirst().orElseThrow(() -> new CustomException("INVALID_OBJECT_OR_METHOD", "Invalid object or method")); } /** - * Checks if the value matches the regex pattern - * @param value - * @param regexPattern - * @return + * Checks if the value matches the regex pattern. + * @param value The value to be checked. + * @param regexPattern The regex pattern to match against. + * @return true if the value matches the pattern, false otherwise. */ public static boolean isValidPattern(String value, String regexPattern) { @@ -878,4 +1139,21 @@ public static boolean isValidPattern(String value, String regexPattern) { return matcher.matches(); } + /** + * Construct a Common Table Expression that returns total count if there is any otherwise return 0L + * @param query + * @param paramsMap + * @param namedParameterJdbcTemplate + * @return + */ + public static Long constructTotalCountCTEAndReturnResult(String query, Map paramsMap, final NamedParameterJdbcTemplate namedParameterJdbcTemplate) { + String cteQuery = "WITH result_cte AS ("+query+"), totalCount_cte AS (SELECT COUNT(*) AS totalRows FROM result_cte) select * from totalCount_cte"; + return namedParameterJdbcTemplate.query(cteQuery, paramsMap, resultSet -> { + if(resultSet.next()) + return resultSet.getLong("totalRows"); + else + return 0L; + }); + } + } diff --git a/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/mapper/GenericRowMapperTest.java b/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/mapper/GenericRowMapperTest.java deleted file mode 100644 index 6234a445c6d..00000000000 --- a/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/mapper/GenericRowMapperTest.java +++ /dev/null @@ -1,127 +0,0 @@ -package org.egov.common.data.mapper; - -import lombok.Getter; -import lombok.Setter; -import org.egov.common.data.query.annotations.Table; -import org.egov.common.data.query.builder.SelectQueryBuilder; -import org.egov.common.data.query.exception.QueryBuilderException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; - -import java.sql.SQLException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -class GenericRowMapperTest { - - - EmbeddedDatabase db; - NamedParameterJdbcTemplate namedParameterJdbcTemplate; - @BeforeEach - public void setUp(){ - db = new EmbeddedDatabaseBuilder().setName("testdb;DATABASE_TO_UPPER=false") - .setType(EmbeddedDatabaseType.H2).addScript("schema.sql").build(); - namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(db); - } - @Test - @DisplayName("should map query to simple object") - void shouldMapQueryResulToSimpleObject() throws SQLException { - - List employeeList = namedParameterJdbcTemplate.query("SELECT * from employee", new GenericRowMapper(Employee.class)); - assertEquals(employeeList.get(0).getId().intValue(), 1); - assertEquals(employeeList.get(0).getName(), "JON"); - } - - @Test - @DisplayName("should map query to nested object") - void shouldMapQueryResulToNestedObject(){ - List employeeList = namedParameterJdbcTemplate.query("SELECT * from employee", new GenericRowMapper(NestedEmployee.class)); - assertEquals(employeeList.get(0).getAmount().getCurrency().getCurrency(), null); - assertEquals(employeeList.get(0).getAmount().getPrice(), 1500, 0); - assertEquals(employeeList.get(1).getAmount().getCurrency().getCurrency(), "INR"); - } - - @Test - @DisplayName("should map query to nested object with prepared sql query") - void shouldMapPreparedQueryResulToNestedObject(){ - String query = "SELECT * from employee where currency=:currency"; - Map queryMap = new HashMap(); - queryMap.put("currency", "INR"); - List employeeList = namedParameterJdbcTemplate.query(query, queryMap, new GenericRowMapper(NestedEmployee.class)); - assertEquals(employeeList.get(0).getId(), 2); - assertEquals(employeeList.get(0).getAmount().getPrice(), 1000); - assertEquals(employeeList.get(0).getAmount().getCurrency().getCurrency(), "INR"); - } - - @Test - @DisplayName("should throw an exception if datatypes between query result and object are incompatible") - void shouldThrowExceptionWhenDataTypeDoNotMatch(){ - assertThrows(RuntimeException.class, () -> namedParameterJdbcTemplate.query("SELECT * from employee", new GenericRowMapper(DataTypeMisMatch.class))); - } - - @Test - @DisplayName("should throw an exception if no default constructor is found") - void shouldThrowExceptionWhenNoDefaultConstructorIsFound(){ - assertThrows(RuntimeException.class, () -> namedParameterJdbcTemplate.query("SELECT * from employee", new GenericRowMapper(NoDefaultConstructor.class))); - } - - @Test - @DisplayName("should map query to simple object") - void shouldMapSelectQueryResulToSimpleObjectWithQueryBuilder() throws SQLException, QueryBuilderException { - Employee e = new Employee(); - e.setId(1); - - SelectQueryBuilder selectQueryBuilderqueryBuilder = new SelectQueryBuilder(); - List employeeList = namedParameterJdbcTemplate.query(selectQueryBuilderqueryBuilder.build(e), selectQueryBuilderqueryBuilder.getParamsMap(), new GenericRowMapper(Employee.class)); - - assertEquals(employeeList.get(0).getId().intValue(), 1); - assertEquals(employeeList.get(0).getName(), "JON"); - } -} - - -@Getter -@Setter -@Table(name = "employee") -class Employee{ - private Integer id; - private String name; -} - -@Getter -class NestedEmployee{ - private int id; - private String name; - private Amount amount; -} -@Getter -class Amount{ - private int price; - private Currency currency; -} -@Getter -class Currency{ - private String currency; -} -@Getter -class DataTypeMisMatch{ - private String price; -} - -@Getter -class NoDefaultConstructor{ - private int price; - public NoDefaultConstructor(int price){ - this.price = price; - } -} - diff --git a/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/query/GenericQueryBuilderTest.java b/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/query/GenericQueryBuilderTest.java index f194c115fd9..30ebaa7e17d 100644 --- a/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/query/GenericQueryBuilderTest.java +++ b/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/query/GenericQueryBuilderTest.java @@ -88,7 +88,7 @@ void shouldBuildSelectQueryForAnEmptyArrayListOfString() throws QueryBuilderExce DummyData data = DummyData.builder() .dummyStringList(strings) .build(); - String expectedQuery = "SELECT * FROM dummyData WHERE 1=1 "; + String expectedQuery = "SELECT * FROM dummyData"; SelectQueryBuilder queryBuilder = new SelectQueryBuilder(); String actualQuery = queryBuilder.build(data); @@ -102,7 +102,7 @@ void shouldHandleNullArrayListOfStringWhileBuildingSelectQuery() throws QueryBui DummyData data = DummyData.builder() .dummyStringList(null) .build(); - String expectedQuery = "SELECT * FROM dummyData WHERE 1=1 "; + String expectedQuery = "SELECT * FROM dummyData"; SelectQueryBuilder queryBuilder = new SelectQueryBuilder(); String actualQuery = queryBuilder.build(data); @@ -135,7 +135,7 @@ void shouldNotUsePrimitiveDataTypesWhileBuildingSelectingQuery() throws QueryBui void shouldNotUseWhereClauseWhenPropertiesAreSetToNullSelectQuery() throws QueryBuilderException { DummyData data = DummyData.builder() .build(); - String expectedQuery = "SELECT * FROM dummyData WHERE 1=1 "; + String expectedQuery = "SELECT * FROM dummyData"; SelectQueryBuilder queryBuilder = new SelectQueryBuilder(); String actualQuery = queryBuilder.build(data); diff --git a/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/repository/GenericRepositoryFindTest.java b/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/repository/GenericRepositoryFindTest.java index ae0a4537126..ff44953f806 100644 --- a/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/repository/GenericRepositoryFindTest.java +++ b/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/repository/GenericRepositoryFindTest.java @@ -106,7 +106,7 @@ void shouldReturnObjectsFromDBForSearchRequest() throws QueryBuilderException { List deleted = result.stream().filter(someObject -> someObject.getIsDeleted() == Boolean.TRUE) .collect(Collectors.toList()); result.removeAll(deleted); - when(selectQueryBuilder.build(any(Object.class))) + when(selectQueryBuilder.build(any(Object.class), anyString())) .thenReturn("Select * from some_table where id='some-id' and isdeleted=false"); when(namedParameterJdbcTemplate.query(any(String.class), any(Map.class), any(SomeRowMapper.class))) .thenReturn(result); @@ -120,7 +120,7 @@ void shouldReturnObjectsFromDBForSearchRequest() throws QueryBuilderException { @Test @DisplayName("get products from db which are deleted") void shouldReturnObjectsFromDBForSearchRequestWithDeletedIncluded() throws QueryBuilderException { - when(selectQueryBuilder.build(any(Object.class))) + when(selectQueryBuilder.build(any(Object.class), anyString())) .thenReturn("Select * from some_table where id='some-id' and otherfield='other-field'"); when(namedParameterJdbcTemplate.query(any(String.class), any(Map.class), any(SomeRowMapper.class))) .thenReturn(someObjects); diff --git a/health-services/libraries/health-services-common/src/test/java/org/egov/common/utils/CommonUtilsTest.java b/health-services/libraries/health-services-common/src/test/java/org/egov/common/utils/CommonUtilsTest.java index 59daa554aff..b50d359d969 100644 --- a/health-services/libraries/health-services-common/src/test/java/org/egov/common/utils/CommonUtilsTest.java +++ b/health-services/libraries/health-services-common/src/test/java/org/egov/common/utils/CommonUtilsTest.java @@ -38,13 +38,12 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.function.Predicate; -import java.util.function.UnaryOperator; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -152,30 +151,30 @@ void shouldGetTheDifferenceOfListsWhenBothTheListsHaveSameNumberOfItems() { assertEquals(0, CommonUtils.getDifference(idList, otherIdList).size()); } - @Test - @DisplayName("should validate the ids as per the given validator") - void shouldValidateTheIdsAsPerTheGivenValidator() { - Set idSet = new HashSet<>(); - idSet.add("some-id"); - idSet.add("other-id"); - UnaryOperator> validator = UnaryOperator.identity(); - - assertDoesNotThrow(() -> CommonUtils.validateIds(idSet, validator)); - } - - @Test - @DisplayName("should throw exception in case an invalid id is found") - void shouldThrowExceptionInCaseAnInvalidIdIsFound() { - Set idSet = new HashSet<>(); - idSet.add("some-id"); - idSet.add("other-id"); - UnaryOperator> validator = (idList) -> { - idList.remove(0); - return idList; - }; - - assertDoesNotThrow(() -> CommonUtils.validateIds(idSet, validator)); - } +// @Test +// @DisplayName("should validate the ids as per the given validator") +// void shouldValidateTheIdsAsPerTheGivenValidator() { +// Set idSet = new HashSet<>(); +// idSet.add("some-id"); +// idSet.add("other-id"); +// UnaryOperator> validator = UnaryOperator.identity(); +// +// assertDoesNotThrow(() -> CommonUtils.validateIds(idSet, validator)); +// } +// +// @Test +// @DisplayName("should throw exception in case an invalid id is found") +// void shouldThrowExceptionInCaseAnInvalidIdIsFound() { +// Set idSet = new HashSet<>(); +// idSet.add("some-id"); +// idSet.add("other-id"); +// UnaryOperator> validator = (idList) -> { +// idList.remove(0); +// return idList; +// }; +// +// assertDoesNotThrow(() -> CommonUtils.validateIds(idSet, validator)); +// } @Test @DisplayName("should get audit details for create") @@ -303,7 +302,7 @@ void shouldReturnRequestObjectWithMismatchedRowVersion() { objList.add(otherObject); objList.add(otherInvalidObject); - Method idMethod = CommonUtils.getMethod("getId", SomeObject.class); + Method idMethod = getMethod("getId", SomeObject.class); assertEquals("some-other-id", CommonUtils.getEntitiesWithMismatchedRowVersion(idToObjMap, objList, idMethod).get(0).getId()); @@ -595,8 +594,7 @@ void shouldSupplySpecifiedNumberOfUuids() { void shouldGetIdFieldNameFromMethod() { SomeObjectWithClientRefId someObject = SomeObjectWithClientRefId.builder() .clientReferenceId("some-client-reference-id").build(); - assertEquals("clientReferenceId", CommonUtils.getIdFieldName(CommonUtils - .getMethod("getClientReferenceId", someObject.getClass()))); + assertEquals("clientReferenceId", CommonUtils.getIdFieldName(getMethod("getClientReferenceId", someObject.getClass()))); } @Test @@ -805,8 +803,8 @@ void shouldCallExceptionHandlerWithCorrectModel() throws JsonProcessingException } @Test - @DisplayName("should throw custom exception when isBulk flag is true") - void shouldCallCustomExceptionWhenIsBulkFlagIsTrue() throws JsonProcessingException { + @DisplayName("should throw custom exception when isBulk flag is false") + void shouldCallCustomExceptionWhenIsBulkFlagIsFalse() throws JsonProcessingException { Map errorDetailsMap = new HashMap<>(); Exception ex = new Exception(); SomeRequest someRequest = SomeRequest.builder() @@ -832,7 +830,7 @@ void shouldCallCustomExceptionWhenIsBulkFlagIsTrue() throws JsonProcessingExcept try { CommonUtils.handleErrors(errorDetailsMap, false, "some-error-code"); } catch (CustomException e) { - assertEquals(e.getErrors().get("some-error-code"), "some-error-message"); + assertEquals(e.getCode(), "some-error-code"); } } diff --git a/health-services/libraries/health-services-models/CHANGELOG.md b/health-services/libraries/health-services-models/CHANGELOG.md new file mode 100644 index 00000000000..c7476cbe79b --- /dev/null +++ b/health-services/libraries/health-services-models/CHANGELOG.md @@ -0,0 +1,35 @@ +All notable changes to this module will be documented in this file. + +## 1.0.21 - 2024-08-07 +- Added UserActionEnum, UserAction Entities, TaskStatus enum +- Added isCascadingProjectDateUpdate in ProjectRequest model +- Removed status field from EgovModel + + +## 1.0.20 - 2024-05-29 +- Added EgovModel, EgovSearchModel, EgovOfflineModel, EgovOfflineSearchModel +- Updated Lombok to 1.18.22 for SuperBuilder annotation support. +- Upgraded to 2.9 LTS +- Changed Dockerfile, base image required for Java 17. + +## 1.0.19 - 2024-02-26 +- Updated project staff search to accept a list of staffIds +- Added senderId and receiverId fields to stock information. + +## 1.0.18 - 2024-02-13 +- Adding user uuid in individual search + +## 1.0.11 - 2023-11-15 +- Client reference id added for member of household +- revert of household search change + +## 1.0.10 +- Downsync models added +- Boundarycode changed to localityCode in household search + +## 1.0.9 +- stock models updated with sender and receiver information fields. + + +## 1.0.0 +- Base version diff --git a/health-services/libraries/health-services-models/Dockerfile b/health-services/libraries/health-services-models/Dockerfile index cd50dd4120d..80abf117900 100644 --- a/health-services/libraries/health-services-models/Dockerfile +++ b/health-services/libraries/health-services-models/Dockerfile @@ -1,8 +1,10 @@ -FROM egovio/alpine-maven-builder-jdk-8:1-master-NA-6036091e AS build +FROM egovio/amazoncorretto:17-alpine3.19 AS build ARG WORK_DIR ARG nexusUsername ARG nexusPassword WORKDIR /app +# Install Maven +RUN apk add --no-cache maven # copy the project files COPY ${WORK_DIR}/pom.xml ./pom.xml COPY ${WORK_DIR}/settings.xml ./settings.xml diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index 1d6eb15e2f0..6ca95c3fe47 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -3,14 +3,13 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.egov.common health-services-models - 1.0.3-SNAPSHOT - + 1.0.21-SNAPSHOT - 8 - 8 + 17 + ${java.version} + ${java.version} UTF-8 @@ -30,6 +29,29 @@ digit-models 1.0.0-SNAPSHOT + + org.egov.services + tracer + 2.9.0-SNAPSHOT + + + jakarta.validation + jakarta.validation-api + 3.0.2 + compile + + + org.hibernate.validator + hibernate-validator + 8.0.1.Final + compile + + + io.swagger + swagger-annotations + 1.5.18 + compile + @@ -45,30 +67,6 @@ - - - - org.apache.maven.plugins - maven-site-plugin - 3.7.1 - - - org.apache.maven.plugins - maven-deploy-plugin - 2.8.2 - - - default-deploy - deploy - - deploy - - - - - - - repo.egovernments.org diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/AdditionalFields.java new file mode 100644 index 00000000000..4d42ce72395 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/AdditionalFields.java @@ -0,0 +1,51 @@ +package org.egov.common.models.core; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * AdditionalFields + */ +@Validated + + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class AdditionalFields { + @JsonProperty("schema") + @Size(min = 2, max = 64) + private String schema = null; + + @JsonProperty("version") + @Min(1) + private Integer version = null; + + @JsonProperty("fields") + @Valid + private List fields = null; + + + public AdditionalFields addFieldsItem(Field fieldsItem) { + if (this.fields == null) { + this.fields = new ArrayList<>(); + } + this.fields.add(fieldsItem); + return this; + } + +} + diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Boundary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Boundary.java new file mode 100644 index 00000000000..f3632bb819b --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Boundary.java @@ -0,0 +1,44 @@ +package org.egov.common.models.core; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.tracer.model.AuditDetails; +import org.springframework.validation.annotation.Validated; + +/** + * Boundary + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Boundary { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("code") + @NotNull + private String code = null; + + @JsonProperty("geometry") + @Valid + private JsonNode geometry = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("additionalDetails") + private JsonNode additionalDetails = null; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java new file mode 100644 index 00000000000..f68ea5cea75 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java @@ -0,0 +1,54 @@ +package org.egov.common.models.core; + + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class EgovModel { + + @JsonProperty("id") + @Size(min = 2, max = 64) + protected String id; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 1000) + protected String tenantId; + + @JsonProperty("source") + protected String source; //TODO what are the various sources and needs comments + + @JsonProperty("rowVersion") + protected Integer rowVersion; + + @JsonProperty("applicationId") //needs comments + protected String applicationId; + + @JsonProperty("hasErrors") + @Builder.Default + protected Boolean hasErrors = Boolean.FALSE; //TODO is this health specific or will this become general. + + @JsonProperty("additionalFields") + @Valid + protected AdditionalFields additionalFields; + + @JsonProperty("auditDetails") + @Valid + protected AuditDetails auditDetails; + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovOfflineModel.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovOfflineModel.java new file mode 100644 index 00000000000..e816f6cd3ce --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovOfflineModel.java @@ -0,0 +1,27 @@ +package org.egov.common.models.core; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class EgovOfflineModel extends EgovModel { + @JsonProperty("clientReferenceId") + @Size(min = 2, max = 64) + protected String clientReferenceId; + + @JsonProperty("clientAuditDetails") + @Valid + protected AuditDetails clientAuditDetails; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovOfflineSearchModel.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovOfflineSearchModel.java new file mode 100644 index 00000000000..9f74f4956b4 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovOfflineSearchModel.java @@ -0,0 +1,20 @@ +package org.egov.common.models.core; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class EgovOfflineSearchModel extends EgovSearchModel { + @JsonProperty("clientReferenceId") + private List clientReferenceId = null; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovSearchModel.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovSearchModel.java new file mode 100644 index 00000000000..ab0113965d3 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovSearchModel.java @@ -0,0 +1,22 @@ +package org.egov.common.models.core; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class EgovSearchModel { + @JsonProperty("id") + @Valid + private List id = null; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Exclude.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Exclude.java new file mode 100644 index 00000000000..48b882c13aa --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Exclude.java @@ -0,0 +1,13 @@ +package org.egov.common.models.core; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +// This annotation is used to mark fields in a model class that should be ignored or excluded when the class is being processed, +// specifically during serialization to JSON or when constructing database queries. +public @interface Exclude { +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Field.java new file mode 100644 index 00000000000..4b24913d764 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Field.java @@ -0,0 +1,37 @@ +package org.egov.common.models.core; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * Field + */ +@Validated + + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class Field { + @JsonProperty("key") + @NotNull + @Size(min = 2, max = 64) + private String key = null; + + @JsonProperty("value") + @NotNull + @Size(min = 1, max = 10000) + private String value = null; + + +} + diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/ProjectSearchURLParams.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/ProjectSearchURLParams.java new file mode 100644 index 00000000000..92fdce4ef8d --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/ProjectSearchURLParams.java @@ -0,0 +1,47 @@ +package org.egov.common.models.core; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * Model class representing common search criteria for API search operations. + * @author kanishq-egov + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ProjectSearchURLParams extends URLParams { + /** + * Used in project search API to specify if response should include project elements + * that are in the preceding hierarchy of matched projects. + */ + @JsonProperty("includeAncestors") + private Boolean includeAncestors; + + /** + * Used in project search API to specify if response should include project elements + * that are in the following hierarchy of matched projects. + */ + @JsonProperty("includeDescendants") + private Boolean includeDescendants; + + /** + * Used in project search API to limit the search results to only those projects whose creation + * date is after the specified 'createdFrom' date. + */ + @JsonProperty("createdFrom") + private Long createdFrom; + + /** + * Used in project search API to limit the search results to only those projects whose creation + * date is before the specified 'createdTo' date. + */ + @JsonProperty("createdTo") + private Long createdTo; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java new file mode 100644 index 00000000000..a7f99255ca7 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java @@ -0,0 +1,21 @@ +package org.egov.common.models.core; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated +public class Role { + private static final String CITIZEN = "CITIZEN"; + private String name; + private String code; + private String description; + private String tenantId; +} \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/SearchResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/SearchResponse.java new file mode 100644 index 00000000000..f688b53e08a --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/SearchResponse.java @@ -0,0 +1,38 @@ +package org.egov.common.models.core; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@ApiModel(description = "Representation of SearchResponse.") +@Validated + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SearchResponse { + + @JsonProperty("TotalCount") + @Getter(AccessLevel.NONE) + private Long totalCount; + + @JsonProperty("Response") + @Builder.Default + private List response = new ArrayList<>(); + + public Long getTotalCount() { + if(totalCount == null) + totalCount = (long) response.size(); + return totalCount; + } +} \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Table.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Table.java new file mode 100644 index 00000000000..8531b0b51b4 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Table.java @@ -0,0 +1,15 @@ +package org.egov.common.models.core; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +// It is used to specify the table name associated with a class. +// When you annotate a class with @Table, it indicates that the class is mapped to a table in the database. +// Used in GenericQueryBuilder +public @interface Table { + String name() default ""; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/URLParams.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/URLParams.java new file mode 100644 index 00000000000..522d5b95eff --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/URLParams.java @@ -0,0 +1,87 @@ +package org.egov.common.models.core; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +/** + * Model class representing common search criteria for API search operations. + * @author kanishq-egov + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class URLParams { + + /** + * The maximum number of records to be returned in the response. + */ + @NotNull + @Min(0) + @Max(1000) + @JsonProperty("limit") + private Integer limit; + + /** + * The offset from which records should be returned in the response. + */ + @NotNull + @Min(0) + @JsonProperty("offset") + private Integer offset; + + /** + * The unique identifier for the tenant. + */ + @NotNull + @JsonProperty("tenantId") + private String tenantId; + + /** + * The epoch time representing point in time since last modification happened in the table. + * Results from this parameter should include both newly created objects and modified objects from this time. + * This criterion aids polling clients to synchronize changes since their last synchronization with the platform. + */ + @JsonProperty("lastChangedSince") + private Long lastChangedSince; + + /** + * Flag indicating whether soft deleted records should be included in search results. + * This flag is used in search APIs to specify if deleted records should be included. + */ + @Builder.Default + @JsonProperty("includeDeleted") + private Boolean includeDeleted = Boolean.FALSE; + + /** + * Sets the URL parameters from the given URLParams object. + * This method allows updating the current URLParams instance with values from another instance. + * + * @param urlParams the URL parameters to set + */ + public void setURLParams(URLParams urlParams) { + // Update limit if provided in the input URLParams + if (urlParams.getLimit() != null) this.limit = urlParams.getLimit(); + + // Update offset if provided in the input URLParams + if (urlParams.getOffset() != null) this.offset = urlParams.getOffset(); + + // Update tenantId if provided in the input URLParams + if (urlParams.getTenantId() != null) this.tenantId = urlParams.getTenantId(); + + // Update lastChangedSince if provided in the input URLParams + if (urlParams.getLastChangedSince() != null) this.lastChangedSince = urlParams.getLastChangedSince(); + + // Update includeDeleted if provided in the input URLParams + if (urlParams.getIncludeDeleted() != null) this.includeDeleted = urlParams.getIncludeDeleted(); + } + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/UpdateBy.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/UpdateBy.java new file mode 100644 index 00000000000..a07a0964a89 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/UpdateBy.java @@ -0,0 +1,13 @@ +package org.egov.common.models.core; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +// This annotation is used to mark specific fields in a class that should be specially considered during update operations +// Used in GenericQueryBuilder +public @interface UpdateBy { +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/validator/CustomIntegerDeserializer.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/validator/CustomIntegerDeserializer.java new file mode 100644 index 00000000000..b5cb00eac27 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/validator/CustomIntegerDeserializer.java @@ -0,0 +1,43 @@ +package org.egov.common.models.core.validator; + +import java.io.IOException; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import org.egov.tracer.model.CustomException; + +// Custom deserializer for Integer values +public class CustomIntegerDeserializer extends StdDeserializer { + + public CustomIntegerDeserializer() { + this(null); + } + + public CustomIntegerDeserializer(Class vc) { + super(vc); + } + + @Override + public Integer deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { + + // Read the JSON tree from the parser + JsonNode node = jsonParser.getCodec().readTree(jsonParser); + System.out.println(node.toString()); + if(node.asLong() > Integer.MAX_VALUE){ + throw new CustomException("INVALID_INPUT","Value must be an Integer"); + } + + // Parse the quantity as an integer + int quantity = node.asInt(); + + // Check if the parsed quantity matches the original string representation + if ((double) quantity != Double.parseDouble(node.asText())) { + throw new CustomException("INVALID_INPUT", "Quantity must be an integer"); + } + + // Return the parsed quantity + return quantity; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AdditionalFields.java index 306fd76b745..3ea950184ae 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AdditionalFields.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AdditionalFields.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Min; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,13 +18,14 @@ * AdditionalFields */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class AdditionalFields { @JsonProperty("schema") @Size(min = 2, max = 64) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Address.java index b0b69f16b1d..6bce525fa97 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Address.java @@ -2,30 +2,30 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.models.core.Boundary; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.DecimalMax; -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.Size; - /** * Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. */ -@ApiModel(description = "Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. ") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated +//TODO should move to common public class Address { @JsonProperty("id") @Size(min = 2, max = 64) @@ -55,7 +55,6 @@ public class Address { @JsonProperty("locationAccuracy") @DecimalMin("0") - @DecimalMax("10000") private Double locationAccuracy = null; @JsonProperty("type") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AddressType.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AddressType.java index 44b904ce16d..9c4931a7005 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AddressType.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AddressType.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonValue; @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public enum AddressType { PERMANENT("PERMANENT"), diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Boundary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Boundary.java deleted file mode 100644 index da9c7cd36af..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Boundary.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.egov.common.models.facility; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - -/** - * Boundary - */ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class Boundary { - @JsonProperty("code") - @NotNull - private String code = null; - - @JsonProperty("name") - private String name = null; - - @JsonProperty("label") - private String label = null; - - @JsonProperty("latitude") - private String latitude = null; - - @JsonProperty("longitude") - private String longitude = null; - - @JsonProperty("children") - @Valid - private List children = null; - - @JsonProperty("materializedPath") - private String materializedPath = null; - - - public Boundary addChildrenItem(Boundary childrenItem) { - if (this.children == null) { - this.children = new ArrayList<>(); - } - this.children.add(childrenItem); - return this; - } - -} - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java index 338afe924b0..3c4d8ba3bf9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java @@ -8,35 +8,25 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * Facility */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class Facility { - @JsonProperty("id") - @Size(min = 2, max = 64) - private String id = null; - - @JsonProperty("clientReferenceId") - @Size(min = 2, max = 64) - private String clientReferenceId = null; - - @JsonProperty("tenantId") - @NotNull - @Size(min = 2, max = 1000) - private String tenantId = null; +public class Facility extends EgovOfflineModel { @JsonProperty("isPermanent") private Boolean isPermanent = true; @@ -55,22 +45,10 @@ public class Facility { @Valid private Address address = null; - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - + //TODO remove this @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkRequest.java index fe151f99b78..36c96818a5b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkRequest.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * FacilityBulkRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkResponse.java index 518d8a0bda7..d58d67eba90 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkResponse.java @@ -8,8 +8,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -17,7 +17,7 @@ * FacilityResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityRequest.java index 84991acd405..be7a61eb30d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityRequest.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * FacilityRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityResponse.java index f4ee54685dd..d0642700db3 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityResponse.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * FacilityResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearch.java index 902b590142b..22f6e9d7a2a 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearch.java @@ -3,32 +3,24 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import java.util.List; - /** * FacilitySearch */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class FacilitySearch { - @JsonProperty("id") - @Valid - private List id = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; +public class FacilitySearch extends EgovOfflineSearchModel { @JsonProperty("isPermanent") private Boolean isPermanent = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearchRequest.java index 02aa94572b7..6a6924bea67 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearchRequest.java @@ -8,20 +8,21 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * FacilitySearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +//TODO should we extend model request info wrapper public class FacilitySearchRequest { @JsonProperty("RequestInfo") @NotNull diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java index e836f7dcc4b..95260a87d83 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java @@ -1,21 +1,21 @@ package org.egov.common.models.facility; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * Field */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor @@ -30,7 +30,7 @@ public class Field { @JsonProperty("value") @NotNull - @Size(min = 2, max = 10000) + @Size(min = 1, max = 10000) private String value = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/TenantRole.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/TenantRole.java index b506a8022a3..d706a86fcff 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/TenantRole.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/TenantRole.java @@ -9,8 +9,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -19,13 +19,14 @@ */ @ApiModel(description = "User role carries the tenant related role information for the user. A user can have multiple roles per tenant based on the need of the tenant. A user may also have multiple roles for multiple tenants.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +//TODO compare with services common public class TenantRole { @JsonProperty("tenantId") @NotNull diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/UserInfo.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/UserInfo.java index 9f815c89caa..a534fb37cfb 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/UserInfo.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/UserInfo.java @@ -9,8 +9,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -19,13 +19,14 @@ */ @ApiModel(description = "This is acting ID token of the authenticated user on the server. Any value provided by the clients will be ignored and actual user based on authtoken will be used on the server.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +//TODO should be imported from common model library public class UserInfo { @JsonProperty("tenantId") @NotNull diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AdditionalFields.java index 34017c09cb6..c38b8ef5b97 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AdditionalFields.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AdditionalFields.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Min; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,13 +18,14 @@ * AdditionalFields */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class AdditionalFields { @JsonProperty("schema") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Address.java index e173fb7cf96..fe0c85041cb 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Address.java @@ -2,31 +2,30 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.models.core.Boundary; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.DecimalMax; -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. */ - @ApiModel(description = "Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. ") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class Address { @JsonProperty("id") @@ -58,7 +57,6 @@ public class Address { @JsonProperty("locationAccuracy") @DecimalMin("0") - @DecimalMax("10000") private Double locationAccuracy = null; @JsonProperty("type") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AddressType.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AddressType.java index 0a8ca8bffa4..93b2a83b51e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AddressType.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AddressType.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonValue; @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public enum AddressType { PERMANENT("PERMANENT"), diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Boundary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Boundary.java deleted file mode 100644 index cdf33544995..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Boundary.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.egov.common.models.household; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.constraints.NotNull; - -/** -* Boundary -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class Boundary { - - @JsonProperty("code") - @NotNull - private String code = null; - - @JsonProperty("name") - private String name = null; - - @JsonProperty("label") - private String label = null; - - @JsonProperty("latitude") - private String latitude = null; - - @JsonProperty("longitude") - private String longitude = null; - -// @JsonProperty("children") -// -// @Valid -// -// -// private List children = null; - - @JsonProperty("materializedPath") - private String materializedPath = null; - - -// public Boundary addChildrenItem(Boundary childrenItem) { -// if (this.children == null) { -// this.children = new ArrayList<>(); -// } -// this.children.add(childrenItem); -// return this; -// } - -} - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Field.java index ba8246ab184..c948934f9c9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Field.java @@ -1,5 +1,8 @@ package org.egov.common.models.household; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; @@ -8,37 +11,27 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * Field */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class Field { - @JsonProperty("key") - @NotNull - - - @Size(min=2,max=64) - +public class Field { + @JsonProperty("key") + @NotNull + @Size(min = 2, max = 64) private String key = null; - @JsonProperty("value") - @NotNull - - - @Size(min=2,max=10000) - + @JsonProperty("value") + @NotNull + @Size(min = 1, max = 10000) private String value = null; - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java index 8cd95af33e9..2452054c4f8 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java @@ -1,47 +1,29 @@ package org.egov.common.models.household; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; -import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; import org.hibernate.validator.constraints.Range; +import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * A representation of Household. */ - @ApiModel(description = "A representation of Household.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class Household { - - @JsonProperty("id") - @Size(min = 2, max = 64) - private String id = null; - - @JsonProperty("tenantId") - @NotNull - @Size(min = 2, max = 1000) - private String tenantId = null; - - @JsonProperty("clientReferenceId") - @Size(min = 2, max = 64) - private String clientReferenceId = null; +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class Household extends EgovOfflineModel { @JsonProperty("memberCount") @NotNull @@ -52,21 +34,9 @@ public class Household { @Valid private Address address = null; - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - + //TODO remove @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkRequest.java index a32ca4cc532..cf1b86cc6d2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * HouseholdRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkResponse.java index 58da38df8af..3646ac55627 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkResponse.java @@ -9,8 +9,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * HouseholdResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor @@ -35,6 +35,10 @@ public class HouseholdBulkResponse { @Valid private List households = null; + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; public HouseholdBulkResponse addHouseholdItem(Household householdItem) { if (this.households == null) { diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java index a63a0742100..c7e016e117d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java @@ -9,29 +9,27 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * A representation of a household member (already registered as an individual) */ @ApiModel(description = "A representation of a household member (already registered as an individual)") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class HouseholdMember{ - - @JsonProperty("id") - @Size(min = 2, max = 64) - private String id = null; +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class HouseholdMember extends EgovOfflineModel { @JsonProperty("householdId") @Size(min = 2, max = 64) @@ -52,26 +50,9 @@ public class HouseholdMember{ @JsonProperty("isHeadOfHousehold") private Boolean isHeadOfHousehold = false; - @JsonProperty("tenantId") - @Size(min = 2, max = 1000) - @NotNull - private String tenantId = null; - - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - + //TODO remove @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkRequest.java index 192ccefd97c..9e45a1f496c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkRequest.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * HouseholdMemberRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkResponse.java index 4b89d6c0919..529336e2052 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkResponse.java @@ -8,8 +8,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -17,7 +17,7 @@ * HouseholdMemberResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor @@ -30,6 +30,11 @@ public class HouseholdMemberBulkResponse { @Valid private org.egov.common.contract.response.ResponseInfo responseInfo = null; + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + @JsonProperty("HouseholdMembers") @Valid private List householdMembers = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberRequest.java index 13721826587..afe2b3a35a2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberRequest.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * HouseholdMemberRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberResponse.java index 559326a3a62..4439b053fa2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberResponse.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * HouseholdMemberResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearch.java index 0f65aab9d25..d435704b4f6 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearch.java @@ -1,52 +1,48 @@ package org.egov.common.models.household; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import java.util.List; - /** * Search model for household member */ @ApiModel(description = "Search model for household member") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class HouseholdMemberSearch { +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class HouseholdMemberSearch extends EgovOfflineSearchModel { - @JsonProperty("id") - private List id = null; + @JsonProperty("clientReferenceId") + private List clientReferenceId = null; @JsonProperty("householdId") - private String householdId = null; + private List householdId = null; @JsonProperty("householdClientReferenceId") - private String householdClientReferenceId = null; + private List householdClientReferenceId = null; @JsonProperty("individualId") - private String individualId = null; + private List individualId = null; @JsonProperty("individualClientReferenceId") - private String individualClientReferenceId = null; + private List individualClientReferenceId = null; @JsonProperty("isHeadOfHousehold") private Boolean isHeadOfHousehold = null; - @JsonProperty("tenantId") - @Valid - private String tenantId = null; - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearchRequest.java index 1d5d0d66bc7..1827c58c249 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearchRequest.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * HouseholdMemberSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdRequest.java index cbd6cc2da5a..2f97fff1203 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * HouseholdRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdResponse.java index f184e37bf27..8659cc34bbf 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdResponse.java @@ -9,14 +9,14 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * HouseholdResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearch.java index 552f974aa47..4ff5ccec51e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearch.java @@ -2,39 +2,47 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; +import org.egov.common.models.core.Exclude; import org.springframework.validation.annotation.Validated; -import java.util.List; - /** * A representation of Household. */ - @ApiModel(description = "A representation of Household.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") - @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class HouseholdSearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; - -// @JsonProperty("memberCount") -// private Integer memberCount = null; - +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class HouseholdSearch extends EgovOfflineSearchModel { @JsonProperty("boundaryCode") private String localityCode = null; + + @Exclude + @JsonProperty("latitude") + @DecimalMin("-90") + @DecimalMax("90") + private Double latitude = null; + + @Exclude + @JsonProperty("longitude") + @DecimalMin("-180") + @DecimalMax("180") + private Double longitude = null; + + /* + * @value unit of measurement in Kilometer + * */ + @Exclude + @JsonProperty("searchRadius") + @DecimalMin("0") + private Double searchRadius = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearchRequest.java index 1d81812a352..57e5377b5ca 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearchRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * HouseholdSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/TenantRole.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/TenantRole.java index 5b863c7e25f..9a37607d2ca 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/TenantRole.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/TenantRole.java @@ -9,8 +9,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ */ @ApiModel(description = "User role carries the tenant related role information for the user. A user can have multiple roles per tenant based on the need of the tenant. A user may also have multiple roles for multiple tenants.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/UserInfo.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/UserInfo.java index b6afe741c3d..648f7640cbe 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/UserInfo.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/UserInfo.java @@ -9,8 +9,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ */ @ApiModel(description = "This is acting ID token of the authenticated user on the server. Any value provided by the clients will be ignored and actual user based on authtoken will be used on the server.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AdditionalFields.java index a16758cdf9b..2546f7f417e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AdditionalFields.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AdditionalFields.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Min; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,13 +18,14 @@ * AdditionalFields */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class AdditionalFields { @JsonProperty("schema") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Address.java index 80070ce7cc4..a6a6a067449 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Address.java @@ -8,25 +8,27 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.models.core.Boundary; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.DecimalMax; -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. */ @ApiModel(description = "Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. ") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder - @JsonIgnoreProperties(ignoreUnknown = true) +@JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class Address { @JsonProperty("id") @@ -75,7 +77,6 @@ public class Address { @DecimalMin("0") - @DecimalMax("10000") private Double locationAccuracy = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AddressType.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AddressType.java index cfbdd36f0e2..d4b8d0b5b00 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AddressType.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AddressType.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonValue; @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public enum AddressType { PERMANENT("PERMANENT"), diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Boundary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Boundary.java deleted file mode 100644 index 2e7185ea6ce..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Boundary.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.egov.common.models.individual; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - -/** -* Boundary -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class Boundary { - @JsonProperty("code") - @NotNull - - - - private String code = null; - - @JsonProperty("name") - - - - private String name = null; - - @JsonProperty("label") - - - - private String label = null; - - @JsonProperty("latitude") - - - - private String latitude = null; - - @JsonProperty("longitude") - - - - private String longitude = null; - - @JsonProperty("children") - - @Valid - - - private List children = null; - - @JsonProperty("materializedPath") - - - - private String materializedPath = null; - - - public Boundary addChildrenItem(Boundary childrenItem) { - if (this.children == null) { - this.children = new ArrayList<>(); - } - this.children.add(childrenItem); - return this; - } - -} - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Field.java index 62cc4f84377..c6b33f09776 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Field.java @@ -1,5 +1,8 @@ package org.egov.common.models.individual; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; @@ -8,37 +11,27 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * Field */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class Field { - @JsonProperty("key") - @NotNull - - - @Size(min=2,max=64) - +public class Field { + @JsonProperty("key") + @NotNull + @Size(min = 2, max = 64) private String key = null; - @JsonProperty("value") - @NotNull - - - @Size(min=2,max=10000) - + @JsonProperty("value") + @NotNull + @Size(min = 1, max = 10000) private String value = null; - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Gender.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Gender.java index d26c5c186d5..06f45867ab5 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Gender.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Gender.java @@ -14,7 +14,9 @@ public enum Gender { FEMALE("FEMALE"), - OTHER("OTHER"); + OTHER("OTHER"), + + TRANSGENDER("TRANSGENDER"); private String value; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Identifier.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Identifier.java index 9bb88701d75..213a67a9446 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Identifier.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Identifier.java @@ -9,15 +9,15 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * Identifier */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java index 5100d887a98..e045ff1fea5 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java @@ -10,11 +10,13 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -24,35 +26,25 @@ */ @ApiModel(description = "A representation of an Individual.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class Individual { - - @JsonProperty("id") - @Size(min = 2, max = 64) - private String id = null; +public class Individual extends EgovOfflineModel { @JsonProperty("individualId") @Size(min = 2, max = 64) private String individualId = null; - @JsonProperty("tenantId") - @NotNull - @Size(min = 2, max = 1000) - private String tenantId = null; - - @JsonProperty("clientReferenceId") - @Size(min = 2, max = 64) - private String clientReferenceId = null; - @JsonProperty("userId") private String userId = null; + @JsonProperty("userUuid") + private String userUuid = null; + @JsonProperty("name") @NotNull @Valid @@ -96,7 +88,7 @@ public class Individual { private String husbandName = null; @JsonProperty("relationship") - @Size(max = 100) + @Size(max = 100, min = 1) private String relationship = null; @JsonProperty("identifiers") @@ -110,26 +102,18 @@ public class Individual { @JsonProperty("photo") private String photo = null; - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - + //TODO remove @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; - @JsonProperty("isSystemUser") private Boolean isSystemUser = Boolean.FALSE; + @JsonProperty("isSystemUserActive") + private Boolean isSystemUserActive = Boolean.TRUE; + + @JsonProperty("userDetails") + private UserDetails userDetails; public Individual addAddressItem(Address addressItem) { if (this.address == null) { diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkRequest.java index 6ec2f502a46..4810780d4e7 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * IndividualRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkResponse.java index a9952743df9..5a185cbaf8d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkResponse.java @@ -9,8 +9,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * IndividualResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor @@ -32,6 +32,11 @@ public class IndividualBulkResponse { @Valid private ResponseInfo responseInfo = null; + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + @JsonProperty("Individual") @Valid private List individual = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualDeleteRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualDeleteRequest.java index 834d1e7f6bf..67c05cc7744 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualDeleteRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualDeleteRequest.java @@ -8,8 +8,8 @@ import lombok.NoArgsConstructor; import org.egov.common.contract.request.RequestInfo; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.List; @Data diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualRequest.java index 2e8857e0176..c8b7927e036 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * IndividualRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualResponse.java index 146f0e3b809..e782b4af9a8 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualResponse.java @@ -9,14 +9,14 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * IndividualResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java index 3d37fdf9b40..d4dc75dfdea 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java @@ -1,41 +1,38 @@ package org.egov.common.models.individual; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; +import org.egov.common.models.core.Exclude; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import java.math.BigDecimal; -import java.util.Date; -import java.util.List; - /** * A representation of an Individual. */ - @ApiModel(description = "A representation of an Individual.") +@ApiModel(description = "A representation of an Individual.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") - @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class IndividualSearch { - @JsonProperty("id") - private List id = null; - +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class IndividualSearch extends EgovOfflineSearchModel { @JsonProperty("individualId") - private String individualId = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; + private List individualId = null; @JsonProperty("name") @Valid @@ -50,28 +47,77 @@ public class IndividualSearch { private Gender gender = null; @JsonProperty("mobileNumber") - private String mobileNumber = null; + private List mobileNumber = null; @JsonProperty("socialCategory") + @Exclude private String socialCategory = null; @JsonProperty("wardCode") + @Exclude private String wardCode = null; + //Exclude annotation to exclude the field during dynamic sql query generation @JsonProperty("individualName") + @Exclude private String individualName = null; @JsonProperty("createdFrom") + @Exclude private BigDecimal createdFrom = null; @JsonProperty("createdTo") + @Exclude private BigDecimal createdTo = null; @JsonProperty("identifier") @Valid + @Exclude private Identifier identifier = null; @JsonProperty("boundaryCode") + @Exclude private String boundaryCode = null; + + @JsonProperty("roleCodes") + @Exclude + private List roleCodes = null; + + @JsonProperty("username") + @Exclude + private List username; + + @JsonProperty("userId") + @Exclude + private List userId; + + @JsonProperty("userUuid") + @Size(min = 1) + @Exclude + private List userUuid; + + @Exclude + @JsonProperty("latitude") + @DecimalMin("-90") + @DecimalMax("90") + private Double latitude; + + @Exclude + @JsonProperty("longitude") + @DecimalMin("-180") + @DecimalMax("180") + private Double longitude; + + /* + * @value unit of measurement in Kilometer + * */ + @Exclude + @JsonProperty("searchRadius") + @DecimalMin("0") + private Double searchRadius; + + + @JsonProperty("type") + private String type; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearchRequest.java index d01730b19e6..a5c3e9cdeaa 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearchRequest.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * IndividualSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Name.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Name.java index 2739d9963e7..7a75ea01913 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Name.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Name.java @@ -8,13 +8,13 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.Size; /** * Name */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Skill.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Skill.java index ec0ac588977..58b905a8522 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Skill.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Skill.java @@ -9,15 +9,15 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * Identifier */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java new file mode 100644 index 00000000000..ea435d9fac9 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java @@ -0,0 +1,37 @@ +package org.egov.common.models.individual; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.user.enums.UserType; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.models.core.Role; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.Size; +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class UserDetails { + @Size(max=180) + @JsonProperty("username") + private String username; + @Size(max=64) + @JsonProperty("password") + private String password; + @Size(min = 2, max = 1000) + @JsonProperty("tenantId") + private String tenantId; + @JsonProperty("roles") + @Valid + private List roles; + @Size(max=50) + @JsonProperty("type") + private UserType userType; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/AdditionalFields.java index 948d8bb5c2c..87d1cd3ea63 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/AdditionalFields.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/AdditionalFields.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Min; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,13 +18,14 @@ * AdditionalFields */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class AdditionalFields { @JsonProperty("schema") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Address.java index ac40eaa04e8..33e05c90d14 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Address.java @@ -3,29 +3,30 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.models.core.Boundary; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.DecimalMax; -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.Size; - /** * Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. */ @ApiModel(description = "Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. ") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder - @JsonIgnoreProperties(ignoreUnknown = true) +@JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class Address { @JsonProperty("id") @@ -67,7 +68,6 @@ public class Address { @DecimalMin("0") - @DecimalMax("10000") private Double locationAccuracy = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Boundary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Boundary.java deleted file mode 100644 index 6cfb2b5c352..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Boundary.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.egov.common.models.product; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - -/** -* Boundary -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class Boundary { - @JsonProperty("code") - @NotNull - - - - private String code = null; - - @JsonProperty("name") - @NotNull - - - - private String name = null; - - @JsonProperty("label") - - - - private String label = null; - - @JsonProperty("latitude") - - - - private String latitude = null; - - @JsonProperty("longitude") - - - - private String longitude = null; - - @JsonProperty("children") - - @Valid - - - private List children = null; - - @JsonProperty("materializedPath") - - - - private String materializedPath = null; - - - public Boundary addChildrenItem(Boundary childrenItem) { - if (this.children == null) { - this.children = new ArrayList<>(); - } - this.children.add(childrenItem); - return this; - } - -} - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Field.java index 2c2f099f003..f27a52cf429 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Field.java @@ -1,5 +1,8 @@ package org.egov.common.models.product; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; @@ -8,37 +11,27 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * Field */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class Field { - @JsonProperty("key") - @NotNull - - - @Size(min=2,max=64) - +public class Field { + @JsonProperty("key") + @NotNull + @Size(min = 2, max = 64) private String key = null; - @JsonProperty("value") - @NotNull - - - @Size(min=2,max=10000) - + @JsonProperty("value") + @NotNull + @Size(min = 1, max = 10000) private String value = null; - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java index 309ed399ecc..afa12e20be2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java @@ -7,32 +7,27 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * Product */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class Product { - - @JsonProperty("id") - private String id = null; +public class Product extends EgovModel { - @JsonProperty("tenantId") - @NotNull - @Size(min=2,max=1000) - private String tenantId = null; @JsonProperty("type") @NotNull @@ -48,18 +43,9 @@ public class Product { @Size(min = 0, max = 1000) private String manufacturer = null; - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - + //TODO remove @JsonProperty("isDeleted") private Boolean isDeleted = null; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductRequest.java index 3811feae8ea..5b209a65ff9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * ProductRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductResponse.java index 9d89ecc7763..52865f39251 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductResponse.java @@ -9,8 +9,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * ProductResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearch.java index 30f02119ab0..5b4907bb571 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearch.java @@ -1,38 +1,36 @@ package org.egov.common.models.product; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovSearchModel; import org.springframework.validation.annotation.Validated; -import java.util.List; - /** * ProductSearch */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class ProductSearch { - - @JsonProperty("id") - private List id = null; +public class ProductSearch extends EgovSearchModel { @JsonProperty("type") private String type = null; @JsonProperty("name") - private String name = null; + private List name = null; @JsonProperty("manufacturer") - private String manufacturer = null; + private List manufacturer = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearchRequest.java index 62cb48ceaab..1f32dad0bf8 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearchRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * ProductSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java index d0dec276973..6f7e34e6b5e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java @@ -1,87 +1,47 @@ package org.egov.common.models.product; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * ProductVariant */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class ProductVariant { - @JsonProperty("id") - - - private String id = null; - - @JsonProperty("tenantId") - @NotNull - @Size(min=2,max=1000) - private String tenantId = null; +public class ProductVariant extends EgovModel { @JsonProperty("productId") @NotNull - - @Size(min = 2, max = 64) - private String productId = null; @JsonProperty("sku") - - @Size(min = 0, max = 1000) - private String sku = null; @JsonProperty("variation") @NotNull - - @Size(min = 0, max = 1000) - private String variation = null; - @JsonProperty("additionalFields") - - @Valid - - - private AdditionalFields additionalFields = null; - + //TODO remove @JsonProperty("isDeleted") - - private Boolean isDeleted = null; - @JsonProperty("rowVersion") - - - private Integer rowVersion = null; - - @JsonProperty("auditDetails") - - @Valid - - - private AuditDetails auditDetails = null; - - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantRequest.java index 9f7bd7074aa..e9d815128a9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * ProductVariantRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantResponse.java index ef76bbb54ce..5584a534753 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantResponse.java @@ -9,8 +9,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * ProductVariantResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearch.java index 8a030c3cc84..1f024529025 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearch.java @@ -1,35 +1,32 @@ package org.egov.common.models.product; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovSearchModel; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.Size; -import java.util.List; - /** * ProductVariantSearch */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class ProductVariantSearch { - - @JsonProperty("id") - private List id = null; +public class ProductVariantSearch extends EgovSearchModel { @JsonProperty("productId") - @Size(min = 2, max = 64) - private String productId = null; + private List productId = null; @JsonProperty("sku") @Size(min = 0, max = 1000) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearchRequest.java index 6485447ea11..880b52f0d1a 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearchRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * ProductVariantSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProjectProductVariant.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProjectProductVariant.java index eca7aff656b..3970c1927d2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProjectProductVariant.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProjectProductVariant.java @@ -8,13 +8,13 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; /** * ProjectProductVariant */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/TenantRole.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/TenantRole.java index 3af69e1d41d..2b2ed233edc 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/TenantRole.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/TenantRole.java @@ -10,8 +10,8 @@ import org.egov.common.contract.request.Role; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -20,7 +20,7 @@ */ @ApiModel(description = "User role carries the tenant related role information for the user. A user can have multiple roles per tenant based on the need of the tenant. A user may also have multiple roles for multiple tenants.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/UserInfo.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/UserInfo.java index 7101032ff40..5c89828c693 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/UserInfo.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/UserInfo.java @@ -10,8 +10,8 @@ import org.egov.common.contract.request.Role; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -20,7 +20,7 @@ */ @ApiModel(description = "This is acting ID token of the authenticated user on the server. Any value provided by the clients will be ignored and actual user based on authtoken will be used on the server.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdditionalFields.java index 5ffbd00271a..819eb9def0c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdditionalFields.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdditionalFields.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Min; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,13 +18,14 @@ * AdditionalFields */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class AdditionalFields { @JsonProperty("schema") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Address.java index ce37429fe51..a928b1cadbf 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Address.java @@ -7,20 +7,21 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.models.core.Boundary; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.DecimalMax; -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. */ @ApiModel(description = "Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. ") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor @@ -56,7 +57,6 @@ public class Address { @JsonProperty("locationAccuracy") @DecimalMin("0") - @DecimalMax("10000") private Double locationAccuracy = null; @JsonProperty("type") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkRequest.java index 87bfe0c5802..a6167611a94 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * BeneficiaryRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkResponse.java index 343a1b78c6b..06c6081b71b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkResponse.java @@ -9,16 +9,16 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; /** -* BeneficiaryResponse -*/ + * BeneficiaryResponse + */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor @@ -26,29 +26,29 @@ @Builder @JsonIgnoreProperties(ignoreUnknown = true) public class BeneficiaryBulkResponse { - @JsonProperty("ResponseInfo") - @NotNull - - @Valid - + @JsonProperty("ResponseInfo") + @NotNull + @Valid private ResponseInfo responseInfo = null; - @JsonProperty("ProjectBeneficiaries") - - @Valid - + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + @JsonProperty("ProjectBeneficiaries") + @Valid private List projectBeneficiaries = null; - public BeneficiaryBulkResponse addProjectBeneficiaryItem(ProjectBeneficiary projectBeneficiaryItem) { - if (this.projectBeneficiaries == null) { + public BeneficiaryBulkResponse addProjectBeneficiaryItem(ProjectBeneficiary projectBeneficiaryItem) { + if (this.projectBeneficiaries == null) { this.projectBeneficiaries = new ArrayList<>(); - } + } this.projectBeneficiaries.add(projectBeneficiaryItem); return this; - } + } } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryRequest.java index aa04c2692a1..cb1e4462721 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * BeneficiaryRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryResponse.java index 31e11433ff3..0b95acf2dc8 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryResponse.java @@ -9,14 +9,14 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * BeneficiaryResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiarySearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiarySearchRequest.java index 5de41e04615..9ca9e718d78 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiarySearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiarySearchRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * BeneficiarySearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Boundary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Boundary.java deleted file mode 100644 index a7db5d3bb41..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Boundary.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.egov.common.models.project; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.constraints.NotNull; - -/** -* Boundary -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class Boundary { - - @JsonProperty("code") - @NotNull - private String code = null; - - @JsonProperty("name") - private String name = null; - - @JsonProperty("label") - private String label = null; - - @JsonProperty("latitude") - private String latitude = null; - - @JsonProperty("longitude") - private String longitude = null; - -// @JsonProperty("children") -// @Valid -// private List children = null; - - @JsonProperty("materializedPath") - private String materializedPath = null; - -// public Boundary addChildrenItem(Boundary childrenItem) { -// if (this.children == null) { -// this.children = new ArrayList<>(); -// } -// this.children.add(childrenItem); -// return this; -// } - -} - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Document.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Document.java index 225eb8fde60..1eb86b7c89f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Document.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Document.java @@ -11,16 +11,16 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * A Object holds the basic data for a Trade License */ @ApiModel(description = "A Object holds the basic data for a Trade License") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Field.java index 33a82b187b7..58360cdaf8e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Field.java @@ -1,5 +1,8 @@ package org.egov.common.models.project; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; @@ -8,22 +11,18 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * Field */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class Field { - +public class Field { @JsonProperty("key") @NotNull @Size(min = 2, max = 64) @@ -31,7 +30,8 @@ public class Field { @JsonProperty("value") @NotNull - @Size(min = 2, max = 10000) + @Size(min = 1, max = 10000) private String value = null; + } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Project.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Project.java index 13378ff0805..586ff410489 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Project.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Project.java @@ -11,7 +11,7 @@ import lombok.Setter; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; +import jakarta.validation.Valid; import java.util.ArrayList; import java.util.List; @@ -20,7 +20,7 @@ */ @ApiModel(description = "The purpose of this object to define the Project for a geography and period") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-08T16:20:57.141+05:30") + @Getter @Setter diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java index 25b96b211ba..6c899a34765 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java @@ -9,33 +9,28 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * A representation of the registration of an entity to a Project. */ @ApiModel(description = "A representation of the registration of an entity to a Project.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectBeneficiary { - @JsonProperty("id") - private String id = null; - - @JsonProperty("tenantId") - @NotNull - @Size(min=2,max=64) - private String tenantId = null; +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ProjectBeneficiary extends EgovOfflineModel { @JsonProperty("projectId") @NotNull @@ -49,30 +44,18 @@ public class ProjectBeneficiary { @JsonProperty("dateOfRegistration") @Min(value = 0, message = "Date must be greater than or equal to 0") private Long dateOfRegistration = null; - - @JsonProperty("clientReferenceId") - @Size(min=2,max=64) - private String clientReferenceId = null; - + /* + * This is the client reference id of the beneficiary type entity (i.e. household, individual) + * */ @JsonProperty("beneficiaryClientReferenceId") @Size(min=2,max=64) private String beneficiaryClientReferenceId = null; - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - + //TODO remove this @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; + @JsonProperty("tag") + private String tag; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiarySearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiarySearch.java index fe61c775b9e..993180f902b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiarySearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiarySearch.java @@ -1,50 +1,39 @@ package org.egov.common.models.project; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.Size; -import java.util.List; - /** * Search model for project beneficiary. */ - @ApiModel(description = "Search model for project beneficiary.") +@ApiModel(description = "Search model for project beneficiary.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectBeneficiarySearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("tenantId") - @Size(min=2,max=1000) - private String tenantId = null; +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ProjectBeneficiarySearch extends EgovOfflineSearchModel { @JsonProperty("projectId") - @Size(min=2,max=64) - private String projectId = null; + private List projectId = null; @JsonProperty("beneficiaryId") - @Size(min=2,max=64) - private String beneficiaryId = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; + private List beneficiaryId = null; @JsonProperty("dateOfRegistration") private Long dateOfRegistration = null; + + @JsonProperty("tag") + private List tag = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java index a8081091e62..60c61e9ddee 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java @@ -1,41 +1,28 @@ package org.egov.common.models.project; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import io.swagger.annotations.ApiModel; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * This object defines the mapping of a facility to a project. */ @ApiModel(description = "This object defines the mapping of a facility to a project.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectFacility { - @JsonProperty("id") - @Size(min = 2, max = 64) - private String id = null; - - @JsonProperty("tenantId") - @NotNull - @Size(min = 2, max = 1000) - private String tenantId = null; +public class ProjectFacility extends EgovModel { @JsonProperty("facilityId") @NotNull @@ -47,21 +34,9 @@ public class ProjectFacility { @Size(min=2,max=64) private String projectId = null; + //TODO remove @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; } \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkRequest.java index 049c0bb3dbb..cd1af9dfcb0 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkRequest.java @@ -10,9 +10,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -20,7 +20,7 @@ * ProjectStaffRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkResponse.java index 89218817564..d2481b16298 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkResponse.java @@ -8,8 +8,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -17,7 +17,7 @@ * ProjectFacilityResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityRequest.java index df428449143..a985decccef 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * ProjectFacilityRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityResponse.java index 40167cfed75..ce862b669c6 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityResponse.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * ProjectFacilityResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-14T20:57:07.075+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilitySearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilitySearch.java index 5f86ad8f19f..adac9f7438d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilitySearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilitySearch.java @@ -1,35 +1,28 @@ package org.egov.common.models.project; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovSearchModel; import org.springframework.validation.annotation.Validated; -import java.util.List; - /** * This object defines the mapping of a facility to a project. */ - @ApiModel(description = "This object defines the mapping of a facility to a project.") +@ApiModel(description = "This object defines the mapping of a facility to a project.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectFacilitySearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("tenantId") - private String tenantId = null; +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ProjectFacilitySearch extends EgovSearchModel { @JsonProperty("facilityId") private List facilityId = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilitySearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilitySearchRequest.java index 244d1c8e5d8..290d8c02805 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilitySearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilitySearchRequest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,15 +11,10 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - /** * ProjectFacilitySearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectProductVariant.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectProductVariant.java index dcbb34004ce..e8841ba5de9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectProductVariant.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectProductVariant.java @@ -8,13 +8,13 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; /** * ProjectProductVariant */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java index 5fb245440f2..da4ae0343e4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * ProjectRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor @@ -38,6 +38,10 @@ public class ProjectRequest { @Size(min=1) private List projects = new ArrayList<>(); + @JsonProperty("isCascadingProjectDateUpdate") + @Valid + private boolean isCascadingProjectDateUpdate = false; + @JsonProperty("apiOperation") @Valid private ApiOperation apiOperation = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java index eb74d3ec81c..64001b9e278 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java @@ -9,33 +9,27 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * This object defines the mapping of a resource to a project. */ @ApiModel(description = "This object defines the mapping of a resource to a project.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectResource { - @JsonProperty("id") - @Size(min=2, max = 64) - private String id = null; - - @JsonProperty("tenantId") - @NotNull - @Size(min=2, max = 1000) - private String tenantId = null; +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ProjectResource extends EgovModel { @JsonProperty("projectId") @NotNull @@ -46,23 +40,15 @@ public class ProjectResource { @NotNull private ProjectProductVariant resource = null; + //TODO remove @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - @JsonProperty("startDate") private Long startDate = null; @JsonProperty("endDate") private Long endDate = null; - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkRequest.java index 00eb95e299d..26b6c095232 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * ProjectResourceRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkResponse.java index 1f121c9db84..e04eb6abd1b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkResponse.java @@ -9,8 +9,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * ProjectResourceResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceRequest.java index c161b22e4e8..d3387b1af96 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * ProjectResourceRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceResponse.java index 9e60ed020ed..cc9a7e5c635 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceResponse.java @@ -9,14 +9,14 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * ProjectResourceResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceSearch.java index 456a54221e2..0178325789b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceSearch.java @@ -1,37 +1,31 @@ package org.egov.common.models.project; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovSearchModel; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.Size; -import java.util.List; - /** * This object defines the mapping of a resource to a project. */ @ApiModel(description = "This object defines the mapping of a resource to a project.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectResourceSearch { - - @JsonProperty("id") - private List id = null; +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ProjectResourceSearch extends EgovSearchModel { @JsonProperty("projectId") - @Size(min=2,max=64) - private String projectId = null; + private List projectId = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceSearchRequest.java index ead04f4f24f..0ad5d439e2f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceSearchRequest.java @@ -2,21 +2,18 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - /** * ProjectResourceSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResponse.java index 21ac8dbe285..54872c4d5a4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResponse.java @@ -9,8 +9,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * ProjectResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearch.java index 15d753cc998..7bb2834bc5f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearch.java @@ -2,62 +2,159 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovSearchModel; +import org.egov.common.models.core.ProjectSearchURLParams; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.Size; - /** -* ProjectSearch -*/ + * ProjectSearch - Model class for searching projects. + * This class includes various fields that can be used to filter projects based on specific criteria. + * It extends EgovSearchModel to inherit common search-related properties. + */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectSearch { - - @JsonProperty("id") - private String id = null; - - @JsonProperty("tenantId") - private String tenantId = null; +public class ProjectSearch extends EgovSearchModel { + /** + * The start date of the project. + * This field can be used to filter projects that start from a specific date. + */ @JsonProperty("startDate") - private Long startDate = null; + private Long startDate; + /** + * The end date of the project. + * This field can be used to filter projects that end by a specific date. + */ @JsonProperty("endDate") - private Long endDate = null; + private Long endDate; + /** + * Indicates if the project has tasks enabled. + * Default value is FALSE. + */ @JsonProperty("isTaskEnabled") - private Boolean isTaskEnabled = false; + private Boolean isTaskEnabled = Boolean.FALSE; + /** + * The parent project ID. + * This field can be used to filter sub-projects of a specific parent project. + * It should be between 2 and 64 characters in length. + */ @JsonProperty("parent") - @Size(min=2,max=64) - private String parent = null; + @Size(min = 2, max = 64) + private String parent; + /** + * The ID of the project type. + * This field can be used to filter projects of a specific type. + */ @JsonProperty("projectTypeId") - private String projectTypeId = null; + private String projectTypeId; + /** + * The ID of the sub-project type. + * This field can be used to filter projects of a specific sub-type. + */ @JsonProperty("subProjectTypeId") - private String subProjectTypeId = null; + private String subProjectTypeId; + /** + * The department associated with the project. + * This field can be used to filter projects of a specific department. + * It should be between 2 and 64 characters in length. + */ @JsonProperty("department") - @Size(min=2,max=64) - private String department = null; - + @Size(min = 2, max = 64) + private String department; + + /** + * The reference ID of the project. + * This field can be used to filter projects by their reference ID. + * It should be between 2 and 100 characters in length. + */ @JsonProperty("referenceId") - @Size(min=2,max=100) - private String referenceId = null; + @Size(min = 2, max = 100) + private String referenceId; + /** + * The boundary code associated with the project. + * This field can be used to filter projects within a specific boundary. + */ @JsonProperty("boundaryCode") - private String boundaryCode = null; - -} - + private String boundaryCode; + + /** + * Used in project search API to specify if response should include project elements + * that are in the preceding hierarchy of matched projects. + */ + @JsonProperty("includeAncestors") + private Boolean includeAncestors; + + /** + * Used in project search API to specify if response should include project elements + * that are in the following hierarchy of matched projects. + */ + @JsonProperty("includeDescendants") + private Boolean includeDescendants; + + /** + * Used in project search API to limit the search results to only those projects whose creation + * date is after the specified 'createdFrom' date. + */ + @JsonProperty("createdFrom") + private Long createdFrom; + + /** + * Used in project search API to limit the search results to only those projects whose creation + * date is before the specified 'createdTo' date. + */ + @JsonProperty("createdTo") + private Long createdTo; + + /** + * The name of the project. + * This field can be used to filter projects by their name. + */ + @JsonProperty("name") + private String name; + + /** + * Sets the URL parameters from the given ProjectSearchURLParams object to this ProjectSearch object. + * This method allows for easy transfer of search parameters from URL to the search model. + * + * @param urlParams The ProjectSearchURLParams object containing the URL parameters. + */ + public void setURLParams(ProjectSearchURLParams urlParams) { + // Call the superclass method to set common URL parameters + + // If the URL parameter includeAncestors is not null, set it to the current object's includeAncestors field + if (urlParams.getIncludeAncestors() != null) { + includeAncestors = urlParams.getIncludeAncestors(); + } + + // If the URL parameter includeDescendants is not null, set it to the current object's includeDescendants field + if (urlParams.getIncludeDescendants() != null) { + includeDescendants = urlParams.getIncludeDescendants(); + } + + // If the URL parameter createdFrom is not null, set it to the current object's createdFrom field + if (urlParams.getCreatedFrom() != null) { + createdFrom = urlParams.getCreatedFrom(); + } + + // If the URL parameter createdTo is not null, set it to the current object's createdTo field + if (urlParams.getCreatedTo() != null) { + createdTo = urlParams.getCreatedTo(); + } + } +} \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearchRequest.java index 5b92236e106..3dc85137b83 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearchRequest.java @@ -2,22 +2,20 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.ProjectSearchURLParams; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - /** * ProjectSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java index f7c0f205af7..78ecda1fa80 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java @@ -1,42 +1,37 @@ package org.egov.common.models.project; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovModel; +import org.springframework.validation.annotation.Validated; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; + import digit.models.coremodels.AuditDetails; import io.swagger.annotations.ApiModel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; /** * This object defines the mapping of a system staff user to a project for a certain period. */ @ApiModel(description = "This object defines the mapping of a system staff user to a project for a certain period.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectStaff { - - @JsonProperty("id") - @Size(min=2,max=64) - private String id = null; - - @JsonProperty("tenantId") - @NotNull - @Size(min=2,max=1000) - private String tenantId = null; +public class ProjectStaff extends EgovModel { @JsonProperty("userId") @NotNull @@ -58,22 +53,9 @@ public class ProjectStaff { @Size(min=2,max=64) private String channel = null; + //TODO remove @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkRequest.java index c23cc976799..c13dc8fcc4b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * ProjectStaffRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkResponse.java index 5c36dd3f503..d73daee5c73 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkResponse.java @@ -9,8 +9,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * ProjectStaffResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffRequest.java index 9c0501849e0..ec7042c5ee0 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * ProjectStaffRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffResponse.java index c9c91fc59e5..49403f8dd95 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffResponse.java @@ -9,14 +9,14 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * ProjectStaffResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearch.java index f32cc34aa7d..7e8cb5ca5ba 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearch.java @@ -1,46 +1,34 @@ package org.egov.common.models.project; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovSearchModel; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.Size; -import java.util.List; - /** -* This object defines the mapping of a system staff user to a project for a certain period. -*/ - @ApiModel(description = "This object defines the mapping of a system staff user to a project for a certain period.") + * This object defines the mapping of a system staff user to a project for a certain period. + */ +@ApiModel(description = "This object defines the mapping of a system staff user to a project for a certain period.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectStaffSearch { - - - @JsonProperty("id") - private List id = null; - - @JsonProperty("tenantId") - @Size(min=2,max=1000) - private String tenantId = null; +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ProjectStaffSearch extends EgovSearchModel { @JsonProperty("staffId") - @Size(min=2,max=64) - private String staffId = null; + private List staffId = null; @JsonProperty("projectId") - @Size(min=2,max=64) - private String projectId = null; + private List projectId = null; @JsonProperty("startDate") private Long startDate = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearchRequest.java index f0e67e8bf1f..f43a480aea1 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearchRequest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,15 +11,10 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - /** * ProjectStaffSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectType.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectType.java index 6aa4942f0a7..b428843e9d3 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectType.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectType.java @@ -10,8 +10,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -20,7 +20,7 @@ */ @ApiModel(description = "This is the master data to capture the metadata of Project") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Role.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Role.java index c1ba8ffa791..fa2e4fee092 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Role.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Role.java @@ -9,15 +9,15 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * minimal representation of the Roles in the system to be carried along in UserInfo with RequestInfo meta data. Actual authorization service to extend this to have more role related attributes */ @ApiModel(description = "minimal representation of the Roles in the system to be carried along in UserInfo with RequestInfo meta data. Actual authorization service to extend this to have more role related attributes ") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Target.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Target.java index e7595853367..5fe7f7dbf7e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Target.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Target.java @@ -15,7 +15,7 @@ * Target */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Getter @Setter diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java index a3689eb112c..9f0160c34b5 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java @@ -1,44 +1,32 @@ package org.egov.common.models.project; -import com.fasterxml.jackson.annotation.JsonIgnore; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * Task */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class Task { - - @JsonProperty("id") - private String id = null; - - @JsonProperty("tenantId") - @NotNull - private String tenantId = null; - - @JsonProperty("clientReferenceId") - @Size(min = 2, max = 64) - private String clientReferenceId = null; +public class Task extends EgovOfflineModel { @JsonProperty("projectId") @NotNull @@ -54,9 +42,8 @@ public class Task { private String projectBeneficiaryClientReferenceId = null; @JsonProperty("resources") - @NotNull @Valid - @Size(min = 1) + @Builder.Default private List resources = new ArrayList<>(); @JsonProperty("plannedStartDate") @@ -81,25 +68,13 @@ public class Task { @Valid private Address address = null; - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - + //TODO remove this @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - @JsonProperty("status") - private String status = null; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; + @NotNull + TaskStatus status = null; public Task addResourcesItem(TaskResource resourcesItem) { this.resources.add(resourcesItem); diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkRequest.java index 48685771d06..87b257e312c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * TaskRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkResponse.java index cdea71cb42b..c0bbfb8e5f5 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkResponse.java @@ -9,8 +9,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * TaskResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor @@ -32,6 +32,11 @@ public class TaskBulkResponse { @Valid private ResponseInfo responseInfo = null; + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + @JsonProperty("Tasks") @NotNull @Valid diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskQuantity.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskQuantity.java new file mode 100644 index 00000000000..6fa7d16610b --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskQuantity.java @@ -0,0 +1,45 @@ +package org.egov.common.models.project; + + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + + +/** + * @author syed-egov + * POJO to capture the metadata of Task + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class TaskQuantity { + + @JsonProperty("id") + private List id = null; + + @JsonProperty("regex") + private String regex = null; + + @JsonProperty("errorMessage") + private String errorMessage = null; + + public TaskQuantity addProductVariantId(String id) { + if (this.id == null) { + this.id = new ArrayList<>(); + } + this.id.add(id); + return this; + } + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskRequest.java index 13fd346d79a..a1d61ed85c1 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * TaskRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java index 986275799d2..8c798d1ef34 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java @@ -3,21 +3,21 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import digit.models.coremodels.AuditDetails; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.models.core.AdditionalFields; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * TaskResource */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor @@ -48,7 +48,7 @@ public class TaskResource { @JsonProperty("quantity") @NotNull - private Long quantity = null; + private Double quantity = null; @JsonProperty("isDelivered") @NotNull @@ -65,5 +65,11 @@ public class TaskResource { @Valid private AuditDetails auditDetails = null; + /** + * Additional fields that may be used for extending the information stored with each task. + */ + @JsonProperty("additionalFields") + @Valid + private AdditionalFields additionalFields = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceRequest.java index b2b59d96d3c..8baedb1acfa 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * TaskRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceResponse.java index 62300dd10ae..4d8c13db362 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceResponse.java @@ -9,8 +9,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * TaskResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResponse.java index 0c4ce1b9ea4..64274a157ea 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResponse.java @@ -9,14 +9,14 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * TaskResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearch.java index 5c9dfcd0e2c..df1857a33f6 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearch.java @@ -1,46 +1,37 @@ package org.egov.common.models.project; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.Size; -import java.util.List; - /** * TaskSearch */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class TaskSearch { - - @JsonProperty("id") - private List id = null; +public class TaskSearch extends EgovOfflineSearchModel { @JsonProperty("projectId") - @Size(min=2,max=64) - private String projectId = null; + private List projectId = null; @JsonProperty("projectBeneficiaryId") - @Size(min=2,max=64) - private String projectBeneficiaryId = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; + private List projectBeneficiaryId = null; @JsonProperty("projectBeneficiaryClientReferenceId") - @Size(min=2,max=64) - private String projectBeneficiaryClientReferenceId = null; + private List projectBeneficiaryClientReferenceId = null; @JsonProperty("plannedStartDate") private Long plannedStartDate = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearchRequest.java index 6d1184da16f..dea1ee10e02 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearchRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * TaskSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskStatus.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskStatus.java new file mode 100644 index 00000000000..a17652a89c0 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskStatus.java @@ -0,0 +1,99 @@ +package org.egov.common.models.project; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Enum representing the various possible statuses for a task. + *

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

+ */ +public enum TaskStatus { + + /** + * Indicates that the task administration has failed. + * This status represents an error or issue encountered during + * the administrative process of the task. + */ + ADMINISTRATION_FAILED("ADMINISTRATION_FAILED"), + + /** + * Indicates that the task administration was successful. + * This status signifies that the task has been processed correctly + * without any issues. + */ + ADMINISTRATION_SUCCESS("ADMINISTRATION_SUCCESS"), + + /** + * Indicates that the beneficiary has refused the task. + * This status means that the individual or entity for whom the task + * was intended has declined to participate or accept it. + */ + BENEFICIARY_REFUSED("BENEFICIARY_REFUSED"), + + /** + * Indicates that the household associated with the task has been closed. + * This status implies that the household is no longer active or + * relevant to the task, possibly due to its closure or other reasons. + */ + CLOSED_HOUSEHOLD("CLOSED_HOUSEHOLD"), + + /** + * Indicates that the task has been delivered. + * This status shows that the task has been successfully completed + * and the deliverables have been provided. + */ + DELIVERED("DELIVERED"), + + /** + * Indicates that the task has not been administered. + * This status signifies that the task has not been processed or + * handled yet. + */ + NOT_ADMINISTERED("NOT_ADMINISTERED"); + + // The string value associated with the task status. + private String value; + + /** + * Constructor to initialize the TaskStatus with a specific string value. + * + * @param value The string value representing the task status. + */ + TaskStatus(String value) { + this.value = value; + } + + /** + * Returns the string representation of the TaskStatus. + * This method is used for serialization of the enum value to JSON. + * + * @return The string value of the task status. + */ + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + /** + * Creates a TaskStatus enum from a string value. + * This method is used for deserialization of the enum value from JSON. + * + * @param text The string value representing the task status. + * @return The TaskStatus enum corresponding to the provided value, + * or null if no match is found. + */ + @JsonCreator + public static TaskStatus fromValue(String text) { + for (TaskStatus status : TaskStatus.values()) { + if (String.valueOf(status.value).equals(text)) { + return status; + } + } + return null; // Return null if no matching status is found + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TenantRole.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TenantRole.java index dbd04dc9343..1feb9f2518f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TenantRole.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TenantRole.java @@ -9,8 +9,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ */ @ApiModel(description = "User role carries the tenant related role information for the user. A user can have multiple roles per tenant based on the need of the tenant. A user may also have multiple roles for multiple tenants.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserActionEnum.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserActionEnum.java new file mode 100644 index 00000000000..1271584b583 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserActionEnum.java @@ -0,0 +1,33 @@ +package org.egov.common.models.project; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public enum UserActionEnum { + CLOSED_HOUSEHOLD("CLOSED_HOUSEHOLD"), + LOCATION_CAPTURE("LOCATION_CAPTURE"), + OTHER("OTHER"); + + private String value; + + UserActionEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static UserActionEnum fromValue(String text) { + for (UserActionEnum status : UserActionEnum.values()) { + if (String.valueOf(status.value).equals(text)) { + return status; + } + } + return null; + } + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserInfo.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserInfo.java index b67c149836a..57afb18c30f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserInfo.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserInfo.java @@ -9,8 +9,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ */ @ApiModel(description = "This is acting ID token of the authenticated user on the server. Any value provided by the clients will be ignored and actual user based on authtoken will be used on the server.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserAction.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserAction.java new file mode 100644 index 00000000000..d58d98996d8 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserAction.java @@ -0,0 +1,109 @@ +package org.egov.common.models.project.useraction; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; +import org.egov.common.models.project.UserActionEnum; +import org.springframework.validation.annotation.Validated; + +/** + * The UserAction class represents an action performed by the logged in user related to a project with + * or without in relation to a beneficiary + * It extends the EgovOfflineModel to inherit common properties. + */ +@Validated +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class UserAction extends EgovOfflineModel { + + /** + * The ID of the project associated with the user action. + * It must be between 2 and 64 characters long and cannot be null. + */ + @JsonProperty("projectId") + @Size(min = 2, max = 64, message = "Project ID must be between 2 and 64 characters") + @NotNull + private String projectId; + + /** + * The latitude coordinate of the user action's location. + * It must be between -90 and 90 degrees and cannot be null. + */ + @JsonProperty("latitude") + @DecimalMin("-90") + @DecimalMax("90") + @NotNull + private Double latitude; + + /** + * The longitude coordinate of the user action's location. + * It must be between -180 and 180 degrees and cannot be null. + */ + @JsonProperty("longitude") + @DecimalMin("-180") + @DecimalMax("180") + @NotNull + private Double longitude; + + /** + * The accuracy of the location measurement in meters. + * It must be a positive number and cannot be null. + */ + @JsonProperty("locationAccuracy") + @DecimalMin("0") + @NotNull + private Double locationAccuracy; + + /** + * The code of the boundary where the user action took place. + * It cannot be null. + */ + @JsonProperty("boundaryCode") + @NotNull + private String boundaryCode; + + /** + * The action performed by the user, represented as a UserActionEnum object. + * It cannot be null. + */ + @JsonProperty("action") + @NotNull + private UserActionEnum action; + + /** + * An optional tag if there is a beneficiary associated with the user action + * It must be between 2 and 64 characters long. + */ + @JsonProperty("beneficiaryTag") + @Size(min = 2, max = 64) + private String beneficiaryTag; + + /** + * An optional tag for the resource associated with the user action. + * It must be between 2 and 64 characters long. + */ + @JsonProperty("resourceTag") + @Size(min = 2, max = 64) + private String resourceTag; + + /** + * A flag indicating whether the user action has been deleted. + * The default value is false. + */ + @JsonProperty("isDeleted") + @Builder.Default + private Boolean isDeleted = false; + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkRequest.java new file mode 100644 index 00000000000..b2bcb8b4f11 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkRequest.java @@ -0,0 +1,64 @@ +package org.egov.common.models.project.useraction; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * The UserActionBulkRequest class is used for handling bulk requests of user actions. + * It contains a RequestInfo object and a list of UserAction objects. + */ +@Validated + + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class UserActionBulkRequest { + + /** + * The RequestInfo object containing metadata about the request. + * This field is mandatory and must be valid. + */ + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo = null; + + /** + * A list of UserAction objects that are part of the bulk request. + * This field is mandatory, must contain at least one item, and must be valid. + * It is initialized to an empty list by default. + */ + @JsonProperty("UserActions") + @NotNull + @Valid + @Size(min = 1) + @Builder.Default + private List userActions = new ArrayList<>(); + + /** + * Adds a UserAction item to the list of user actions in the bulk request. + * This method is useful for incrementally building the list of user actions. + * + * @param userAction The UserAction object to be added to the list. + * @return The current instance of UserActionBulkRequest with the new UserAction added. + */ + public UserActionBulkRequest addTaskItem(UserAction userAction) { + this.userActions.add(userAction); + return this; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkResponse.java new file mode 100644 index 00000000000..f8698b676bd --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkResponse.java @@ -0,0 +1,70 @@ +package org.egov.common.models.project.useraction; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +/** + * The UserActionBulkResponse class is used for handling bulk responses of user actions. + * It contains a ResponseInfo object, a total count of user actions, and a list of UserAction objects. + */ +@Validated +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class UserActionBulkResponse { + + /** + * The ResponseInfo object containing metadata about the response. + * This field is mandatory and must be valid. + */ + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo = null; + + /** + * The total count of user actions in the response. + * It is initialized to 0 by default. + */ + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + + /** + * A list of UserAction objects that are part of the bulk response. + * This field is mandatory and must be valid. + */ + @JsonProperty("UserActions") + @NotNull + @Valid + private List userActions = null; + + /** + * Adds a UserAction item to the list of user actions in the bulk response. + * This method is useful for incrementally building the list of user actions. + * + * @param userActionItem The UserAction object to be added to the list. + * @return The current instance of UserActionBulkResponse with the new UserAction added. + */ + public UserActionBulkResponse addUserAction(UserAction userActionItem) { + if (this.userActions == null) { + this.userActions = new ArrayList<>(); + } + this.userActions.add(userActionItem); + return this; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearch.java new file mode 100644 index 00000000000..0e2051b6be6 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearch.java @@ -0,0 +1,55 @@ +package org.egov.common.models.project.useraction; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; +import org.springframework.validation.annotation.Validated; + +/** + * The UserActionSearch class is used for searching user actions based on various criteria. + * It extends the EgovOfflineSearchModel to inherit common search properties. + */ +@Validated +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class UserActionSearch extends EgovOfflineSearchModel { + + /** + * A userId to filter the user actions. + */ + @JsonProperty("createdBy") + private String createdBy; + + /** + * A project ID to filter the user actions. + */ + @JsonProperty("projectId") + private String projectId; + + /** + * A beneficiary tag to filter the user actions. + */ + @JsonProperty("beneficiaryTag") + private String beneficiaryTag; + + /** + * A resource tag to filter the user actions. + */ + @JsonProperty("resourceTag") + private String resourceTag; + + /** + * A boundary code to filter the user actions. + */ + @JsonProperty("boundaryCode") + private String boundaryCode; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearchRequest.java new file mode 100644 index 00000000000..1bf43eb8ced --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearchRequest.java @@ -0,0 +1,44 @@ +package org.egov.common.models.project.useraction; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.springframework.validation.annotation.Validated; + +/** + * The UserActionSearchRequest class is used to encapsulate the request information + * for searching user actions. It includes the request metadata and the search criteria. + */ +@Validated +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class UserActionSearchRequest { + + /** + * The RequestInfo object contains metadata about the request, such as the + * API version, request timestamp, and user details. This field is mandatory + * and must be valid. + */ + @JsonProperty("RequestInfo") + @NotNull + @Valid + private org.egov.common.contract.request.RequestInfo requestInfo; + + /** + * The UserAction object contains the search criteria for filtering user actions. + * This includes various filters such as project IDs, beneficiary tags, resource tags, + * and boundary codes. This field is mandatory and must be valid. + */ + @JsonProperty("UserAction") + @NotNull + @Valid + private UserActionSearch userAction; +} \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java new file mode 100644 index 00000000000..9cdc553bb92 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java @@ -0,0 +1,60 @@ +package org.egov.common.models.referralmanagement; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; +import org.egov.common.models.project.AdditionalFields; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class Referral extends EgovOfflineModel { + + @JsonProperty("projectBeneficiaryId") + @Size(min = 2, max = 64) + private String projectBeneficiaryId; + + @JsonProperty("projectBeneficiaryClientReferenceId") + @Size(min = 2, max = 64) + private String projectBeneficiaryClientReferenceId; + + @JsonProperty("referrerId") + @Size(min = 2, max = 64) + private String referrerId; + + @JsonProperty("recipientType") + private String recipientType; + + @JsonProperty("recipientId") + @Size(min = 2, max = 64) + private String recipientId; + + @JsonProperty("reasons") + @NotNull + @Size(min=1) + private List reasons; + + @JsonProperty("referralCode") + @Size(max=100) + private String referralCode; + + @JsonProperty("sideEffect") + private SideEffect sideEffect; + + @JsonProperty("isDeleted") + private Boolean isDeleted = Boolean.FALSE; + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkRequest.java new file mode 100644 index 00000000000..43beca385c8 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkRequest.java @@ -0,0 +1,46 @@ +package org.egov.common.models.referralmanagement; + +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 jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ReferralBulkRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo; + + @JsonProperty("Referrals") + @NotNull + @Valid + @Size(min = 1) + private List referrals; + + /** + * Add a Referral item to the list of Referrals in the bulk request. + * + * @param referralItem The Referral item to add to the request. + * @return The updated ReferralBulkRequest. + */ + public ReferralBulkRequest addReferralItem(Referral referralItem) { + if(Objects.isNull(referrals)) + referrals = new ArrayList<>(); + if(Objects.nonNull(referralItem)) + referrals.add(referralItem); + return this; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkResponse.java new file mode 100644 index 00000000000..7dfa73883aa --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkResponse.java @@ -0,0 +1,49 @@ +package org.egov.common.models.referralmanagement; + +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 jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ReferralBulkResponse { + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo; + + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + + @JsonProperty("Referrals") + @NotNull + @Valid + private List referrals; + + /** + * Add a Referral item to the list of Referrals in the bulk response. + * + * @param referralItem The Referral item to add to the response. + * @return The updated ReferralBulkResponse. + */ + public ReferralBulkResponse addReferralItem(Referral referralItem) { + if(Objects.isNull(referrals)) + referrals = new ArrayList<>(); + if(Objects.nonNull(referralItem)) + referrals.add(referralItem); + return this; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralRequest.java new file mode 100644 index 00000000000..c21a6e2a3a5 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralRequest.java @@ -0,0 +1,27 @@ +package org.egov.common.models.referralmanagement; + +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 jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ReferralRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo; + + @JsonProperty("Referral") + @NotNull + @Valid + private Referral referral; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralResponse.java new file mode 100644 index 00000000000..3cf99fc9073 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralResponse.java @@ -0,0 +1,27 @@ +package org.egov.common.models.referralmanagement; + +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 jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ReferralResponse { + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo; + + @JsonProperty("Referral") + @NotNull + @Valid + private Referral referral; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearch.java new file mode 100644 index 00000000000..9c3ef87889e --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearch.java @@ -0,0 +1,35 @@ +package org.egov.common.models.referralmanagement; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class ReferralSearch extends EgovOfflineSearchModel { + + @JsonProperty("projectBeneficiaryId") + private List projectBeneficiaryId; + + @JsonProperty("projectBeneficiaryClientReferenceId") + private List projectBeneficiaryClientReferenceId; + + @JsonProperty("sideEffectId") + private List sideEffectId; + + @JsonProperty("sideEffectClientReferenceId") + private List sideEffectClientReferenceId; + + @JsonProperty("referrerId") + private List referrerId; + + @JsonProperty("recipientId") + private List recipientId; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearchRequest.java new file mode 100644 index 00000000000..e872c6f1df0 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearchRequest.java @@ -0,0 +1,26 @@ +package org.egov.common.models.referralmanagement; + +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 jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ReferralSearchRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo; + + @JsonProperty("Referral") + @Valid + private ReferralSearch referral; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/Downsync.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/Downsync.java new file mode 100644 index 00000000000..c53e28da3fe --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/Downsync.java @@ -0,0 +1,50 @@ +package org.egov.common.models.referralmanagement.beneficiarydownsync; + +import java.util.List; + +import org.egov.common.models.household.Household; +import org.egov.common.models.household.HouseholdMember; +import org.egov.common.models.individual.Individual; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.models.project.Task; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class Downsync { + + @JsonProperty("Households") + private List Households; + + @JsonProperty("HouseholdMembers") + private List HouseholdMembers; + + @JsonProperty("Individuals") + private List Individuals; + + @JsonProperty("ProjectBeneficiaries") + private List ProjectBeneficiaries; + + @JsonProperty("Tasks") + private List Tasks; + + @JsonProperty("SideEffects") + private List SideEffects; + + @JsonProperty("Referrals") + private List Referrals; + + @JsonProperty("DownsyncCriteria") + private DownsyncCriteria downsyncCriteria; + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncCriteria.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncCriteria.java new file mode 100644 index 00000000000..71816f7849f --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncCriteria.java @@ -0,0 +1,39 @@ +package org.egov.common.models.referralmanagement.beneficiarydownsync; + +import jakarta.validation.constraints.NotNull; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DownsyncCriteria { + + @NotNull + private String locality; + + private Long lastSyncedTime; + + @NotNull + private String projectId; + + @NotNull + private String tenantId; + + @Default + private Boolean includeDeleted = false; + + @Default + private Integer offset = 0; + + @Default + private Integer limit = 50; + + private Long totalCount; +} + diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncRequest.java new file mode 100644 index 00000000000..6db2a1f97b9 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncRequest.java @@ -0,0 +1,23 @@ +package org.egov.common.models.referralmanagement.beneficiarydownsync; + +import org.egov.common.contract.request.RequestInfo; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DownsyncRequest { + + @JsonProperty("RequestInfo") + private RequestInfo requestInfo; + + @JsonProperty("DownsyncCriteria") + private DownsyncCriteria downsyncCriteria; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncResponse.java new file mode 100644 index 00000000000..23635cf119a --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncResponse.java @@ -0,0 +1,23 @@ +package org.egov.common.models.referralmanagement.beneficiarydownsync; + +import org.egov.common.contract.response.ResponseInfo; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DownsyncResponse { + + @JsonProperty("ResponseInfo") + private ResponseInfo responseInfo; + + @JsonProperty("Downsync") + private Downsync downsync; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferral.java new file mode 100644 index 00000000000..2c68467c843 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferral.java @@ -0,0 +1,57 @@ +package org.egov.common.models.referralmanagement.hfreferral; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; +import org.egov.common.models.project.AdditionalFields; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class HFReferral extends EgovOfflineModel { + + @JsonProperty("projectId") + @Size(min = 2, max = 64) + private String projectId; + + @JsonProperty("projectFacilityId") + @Size(min = 2, max = 64) + private String projectFacilityId; + + @JsonProperty("symptom") + @NotNull + @Size(min = 2, max = 256) + private String symptom; + + @JsonProperty("symptomSurveyId") + @Size(min = 2, max = 100) + private String symptomSurveyId; + + @JsonProperty("beneficiaryId") + @Size(max=100) + private String beneficiaryId; + + @JsonProperty("referralCode") + @Size(max=100) + private String referralCode; + + @JsonProperty("nationalLevelId") + @Size(max=100) + private String nationalLevelId; + + //TODO remove this + @JsonProperty("isDeleted") + private Boolean isDeleted = Boolean.FALSE; + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkRequest.java new file mode 100644 index 00000000000..bd9080b6c80 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkRequest.java @@ -0,0 +1,46 @@ +package org.egov.common.models.referralmanagement.hfreferral; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class HFReferralBulkRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo; + + @JsonProperty("HFReferrals") + @NotNull + @Valid + @Size(min = 1) + private List hfReferrals; + + /** + * Add a HfReferral item to the list of HfReferrals in the bulk request. + * + * @param hfReferralItem The HfReferral item to add to the request. + * @return The updated HFReferralBulkRequest. + */ + public HFReferralBulkRequest addHFReferralItem(HFReferral hfReferralItem) { + if(Objects.isNull(hfReferrals)) + hfReferrals = new ArrayList<>(); + if(Objects.nonNull(hfReferralItem)) + hfReferrals.add(hfReferralItem); + return this; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java new file mode 100644 index 00000000000..a561ef4f8a4 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java @@ -0,0 +1,44 @@ +package org.egov.common.models.referralmanagement.hfreferral; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import 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.response.ResponseInfo; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class HFReferralBulkResponse { + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo; + + @JsonProperty("HFReferrals") + @NotNull + @Valid + private List hfReferrals; + + /** + * Add a HfReferral item to the list of HfReferrals in the bulk response. + * + * @param hfReferralItem The HfReferral item to add to the response. + * @return The updated HFReferralBulkRequest. + */ + public HFReferralBulkResponse addReferralItem(HFReferral hfReferralItem) { + if(Objects.isNull(hfReferrals)) + hfReferrals = new ArrayList<>(); + if(Objects.nonNull(hfReferralItem)) + hfReferrals.add(hfReferralItem); + return this; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralRequest.java new file mode 100644 index 00000000000..1c305c56341 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralRequest.java @@ -0,0 +1,27 @@ +package org.egov.common.models.referralmanagement.hfreferral; + +import 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.request.RequestInfo; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class HFReferralRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo; + + @JsonProperty("HFReferral") + @NotNull + @Valid + private HFReferral hfReferral; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralResponse.java new file mode 100644 index 00000000000..97821467ac9 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralResponse.java @@ -0,0 +1,27 @@ +package org.egov.common.models.referralmanagement.hfreferral; + +import 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.response.ResponseInfo; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class HFReferralResponse { + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo; + + @JsonProperty("HFReferral") + @NotNull + @Valid + private HFReferral hfReferral; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearch.java new file mode 100644 index 00000000000..26d56c565ad --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearch.java @@ -0,0 +1,38 @@ +package org.egov.common.models.referralmanagement.hfreferral; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class HFReferralSearch extends EgovOfflineSearchModel { + + @JsonProperty("facilityId") + private List facilityId; + + @JsonProperty("projectId") + private String projectId; + + @JsonProperty("symptom") + private List symptom; + + @JsonProperty("symptomSurveyId") + private List symptomSurveyId; + + @JsonProperty("beneficiaryId") + private List beneficiaryId; + + @JsonProperty("referralCode") + private List referralCode; + + @JsonProperty("nationalLevelId") + private List nationalLevelId; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearchRequest.java new file mode 100644 index 00000000000..1692ca692d5 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearchRequest.java @@ -0,0 +1,26 @@ +package org.egov.common.models.referralmanagement.hfreferral; + +import 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.request.RequestInfo; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class HFReferralSearchRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo; + + @JsonProperty("HFReferral") + @Valid + private HFReferralSearch hfReferral; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java new file mode 100644 index 00000000000..f9f3041aeb5 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java @@ -0,0 +1,51 @@ +package org.egov.common.models.referralmanagement.sideeffect; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; +import org.egov.common.models.project.AdditionalFields; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class SideEffect extends EgovOfflineModel { + + @JsonProperty("taskId") + @Size(min = 2, max = 64) + private String taskId; + + @JsonProperty("taskClientReferenceId") + @NotNull + @Size(min = 2, max = 64) + private String taskClientReferenceId; + + @JsonProperty("projectBeneficiaryId") + @Size(min = 2, max = 64) + private String projectBeneficiaryId; + + @JsonProperty("projectBeneficiaryClientReferenceId") + @Size(min = 2, max = 64) + private String projectBeneficiaryClientReferenceId; + + @JsonProperty("symptoms") + @NotNull + @Size(min=1) + private List symptoms; + + //TODO remove this + @JsonProperty("isDeleted") + private Boolean isDeleted = Boolean.FALSE; + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java new file mode 100644 index 00000000000..fed08c092de --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java @@ -0,0 +1,47 @@ +package org.egov.common.models.referralmanagement.sideeffect; + +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 jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SideEffectBulkRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo; + + @JsonProperty("SideEffects") + @NotNull + @Valid + @Size(min=1) + private List sideEffects = new ArrayList<>(); + + /** + * Add a SideEffect item to the list of side effects in the request. + * + * @param sideEffectItem The SideEffect item to add to the request. + * @return The updated SideEffectBulkRequest. + */ + public SideEffectBulkRequest addSideEffectItem(SideEffect sideEffectItem) { + if(Objects.isNull(sideEffects)) + sideEffects = new ArrayList<>(); + if(Objects.nonNull(sideEffectItem)) + this.sideEffects.add(sideEffectItem); + return this; + } + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java new file mode 100644 index 00000000000..d22245c5a79 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java @@ -0,0 +1,50 @@ +package org.egov.common.models.referralmanagement.sideeffect; + +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 jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SideEffectBulkResponse { + + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo; + + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + + @JsonProperty("SideEffects") + @NotNull + @Valid + private List sideEffects = new ArrayList<>(); + + /** + * Add a SideEffect item to the list of side effects in the response. + * + * @param sideEffectItem The SideEffect item to add to the response. + * @return The updated SideEffectBulkResponse. + */ + public SideEffectBulkResponse addSideEffectItem(SideEffect sideEffectItem) { + if(Objects.isNull(sideEffects)) + sideEffects = new ArrayList<>(); + if(Objects.nonNull(sideEffectItem)) + this.sideEffects.add(sideEffectItem); + return this; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java new file mode 100644 index 00000000000..893e9efb526 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java @@ -0,0 +1,27 @@ +package org.egov.common.models.referralmanagement.sideeffect; + +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 jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SideEffectRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo; + + @JsonProperty("SideEffect") + @NotNull + @Valid + private SideEffect sideEffect; +} \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java new file mode 100644 index 00000000000..8dbc9a0a89c --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java @@ -0,0 +1,29 @@ +package org.egov.common.models.referralmanagement.sideeffect; + +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 jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SideEffectResponse { + + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo; + + @JsonProperty("SideEffect") + @NotNull + @Valid + private SideEffect sideEffect; + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java new file mode 100644 index 00000000000..4a37ded59b3 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java @@ -0,0 +1,24 @@ +package org.egov.common.models.referralmanagement.sideeffect; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +public class SideEffectSearch extends EgovOfflineSearchModel { + + @JsonProperty("taskId") + private List taskId; + + @JsonProperty("taskClientReferenceId") + private List taskClientReferenceId; + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java new file mode 100644 index 00000000000..a5248c5d6e7 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java @@ -0,0 +1,26 @@ +package org.egov.common.models.referralmanagement.sideeffect; + +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 jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SideEffectSearchRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo; + + @JsonProperty("SideEffect") + @Valid + private SideEffectSearch sideEffect; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AdditionalFields.java index 9c94c91ea95..ef65681acc2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AdditionalFields.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AdditionalFields.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Min; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,14 +18,14 @@ * AdditionalFields */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) - +@Deprecated public class AdditionalFields { @JsonProperty("schema") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Address.java index d5ae3b61517..dacc7c3c5b7 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Address.java @@ -3,30 +3,31 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.models.core.Boundary; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.DecimalMax; -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. */ @ApiModel(description = "Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. ") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class Address { @JsonProperty("id") @Size(min = 2, max = 64) @@ -51,7 +52,6 @@ public class Address { @JsonProperty("locationAccuracy") @DecimalMin("0") - @DecimalMax("10000") private Double locationAccuracy = null; @JsonProperty("type") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AddressType.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AddressType.java index 1ca1084f080..b39fcffd32d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AddressType.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AddressType.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonValue; @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public enum AddressType { PERMANENT("PERMANENT"), diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Boundary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Boundary.java deleted file mode 100644 index 16bc59bfa05..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Boundary.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.egov.common.models.stock; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - -/** -* Boundary -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class Boundary { - @JsonProperty("code") - @NotNull - - - - private String code = null; - - @JsonProperty("name") - - - - private String name = null; - - @JsonProperty("label") - - - - private String label = null; - - @JsonProperty("latitude") - - - - private String latitude = null; - - @JsonProperty("longitude") - - - - private String longitude = null; - - @JsonProperty("children") - - @Valid - - - private List children = null; - - @JsonProperty("materializedPath") - - - - private String materializedPath = null; - - - public Boundary addChildrenItem(Boundary childrenItem) { - if (this.children == null) { - this.children = new ArrayList<>(); - } - this.children.add(childrenItem); - return this; - } - -} - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Field.java index 73dab0bcb93..f040c0d8a28 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Field.java @@ -1,5 +1,8 @@ package org.egov.common.models.stock; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; @@ -8,37 +11,27 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * Field */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class Field { - @JsonProperty("key") - @NotNull - - - @Size(min=2,max=64) - +public class Field { + @JsonProperty("key") + @NotNull + @Size(min = 2, max = 64) private String key = null; - @JsonProperty("value") - @NotNull - - - @Size(min=1,max=10000) - + @JsonProperty("value") + @NotNull + @Size(min = 1, max = 10000) private String value = null; - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/ReferenceIdType.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/ReferenceIdType.java new file mode 100644 index 00000000000..7b5943c3493 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/ReferenceIdType.java @@ -0,0 +1,32 @@ +package org.egov.common.models.stock; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonValue; + +@JsonIgnoreProperties(ignoreUnknown = true) +public enum ReferenceIdType { + PROJECT("PROJECT"), + OTHER("OTHER"); + private String value; + + ReferenceIdType(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static ReferenceIdType fromValue(String text) { + for (ReferenceIdType b : ReferenceIdType.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/SenderReceiverType.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/SenderReceiverType.java new file mode 100644 index 00000000000..e5b1924574a --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/SenderReceiverType.java @@ -0,0 +1,34 @@ +package org.egov.common.models.stock; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonValue; + +@JsonIgnoreProperties(ignoreUnknown = true) +public enum SenderReceiverType { + WAREHOUSE("WAREHOUSE"), + + STAFF("STAFF"); + + private String value; + + SenderReceiverType(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static SenderReceiverType fromValue(String text) { + for (SenderReceiverType b : SenderReceiverType.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java index 877436da62d..1ec63f96c54 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java @@ -1,103 +1,99 @@ package org.egov.common.models.stock; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import digit.models.coremodels.AuditDetails; import lombok.AllArgsConstructor; import lombok.Builder; +import lombok.Builder.Default; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * Stock */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class Stock { - @JsonProperty("id") - @Size(min=2, max=64) - private String id = null; - - @JsonProperty("clientReferenceId") - @Size(min=2, max=64) - private String clientReferenceId = null; - - @JsonProperty("tenantId") - @NotNull - @Size(min=2, max=1000) - private String tenantId = null; - - @JsonProperty("facilityId") - @NotNull - @Size(min=2, max=64) - private String facilityId = null; +public class Stock extends EgovOfflineModel { + /* product fields */ @JsonProperty("productVariantId") @NotNull @Size(min=2, max=64) - private String productVariantId = null; + private String productVariantId; @JsonProperty("quantity") @NotNull - private Integer quantity = null; + @Min(value = 1, message = "Minimum value cannot be less than 1") + @Max(value = Integer.MAX_VALUE, message = "Value exceeds maximum allowable limit") + private Integer quantity; + /* project id in-case of health */ @JsonProperty("referenceId") - private String referenceId = null; + private String referenceId; @JsonProperty("referenceIdType") - @Size(min=2, max=64) - private String referenceIdType = null; + @NotNull(message = "referenceIdType must be PROJECT or OTHER") + @Valid + private ReferenceIdType referenceIdType; + // transaction fields @JsonProperty("transactionType") - @NotNull + @NotNull(message = "transactionType must be either RECEIVED or DISPATCHED") @Valid - private TransactionType transactionType = null; + private TransactionType transactionType; @JsonProperty("transactionReason") @Valid - private TransactionReason transactionReason = null; + private TransactionReason transactionReason; - @JsonProperty("transactingPartyId") + @JsonProperty("senderId") @NotNull @Size(min=2, max=64) - private String transactingPartyId = null; + private String senderId; - @JsonProperty("transactingPartyType") + @JsonProperty("senderType") + @NotNull(message = "Sender Type can be either WAREHOUSE or STAFF") + @Valid + private SenderReceiverType senderType; + + @JsonProperty("receiverId") @NotNull @Size(min=2, max=64) - private String transactingPartyType = null; + private String receiverId; + + @JsonProperty("receiverType") + @NotNull(message = "Receiver Type can be either WAREHOUSE or STAFF") + @Valid + private SenderReceiverType receiverType; @JsonProperty("wayBillNumber") @Size(min = 2, max = 200) - private String wayBillNumber = null; - - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; + private String wayBillNumber; + //TODO remove this @JsonProperty("isDeleted") + @Default private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; + @JsonProperty("dateOfEntry") + private Long dateOfEntry; - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkRequest.java index 7b42fbb4f27..696a7b9e41e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkRequest.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * StockRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkResponse.java index c1057a595c4..cea7c46b8e5 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkResponse.java @@ -8,8 +8,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -17,7 +17,7 @@ * StockResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java index 9b94d58a170..b8fc052ce68 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java @@ -8,36 +8,26 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * StockReconciliation */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class StockReconciliation { - @JsonProperty("id") - @Size(min=2, max=64) - private String id = null; - - @JsonProperty("clientReferenceId") - @Size(min=2, max=64) - private String clientReferenceId = null; - - @JsonProperty("tenantId") - @NotNull - @Size(min=2, max=1000) - private String tenantId = null; +public class StockReconciliation extends EgovOfflineModel { @JsonProperty("facilityId") @NotNull @@ -68,21 +58,9 @@ public class StockReconciliation { @JsonProperty("dateOfReconciliation") private Long dateOfReconciliation = null; - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - + //TODO remove this @JsonProperty("isDeleted") private Boolean isDeleted = null; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkRequest.java index 169f0f86944..b9f01d68f98 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkRequest.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * StockReconciliationRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkResponse.java index ccc34392562..caea2ead604 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkResponse.java @@ -8,8 +8,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -17,7 +17,7 @@ * StockReconciliationResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationRequest.java index d5794fad6ca..58845227bf2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationRequest.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * StockReconciliationRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationResponse.java index f05d79ef8db..409223db9ca 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationResponse.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * StockReconciliationResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearch.java index a808934a953..64dd63ac5b9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearch.java @@ -1,42 +1,33 @@ package org.egov.common.models.stock; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Size; -import java.util.List; - /** * StockReconciliationSearch */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class StockReconciliationSearch { - @JsonProperty("id") - @Valid - private List id = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; +public class StockReconciliationSearch extends EgovOfflineSearchModel { @JsonProperty("facilityId") - @Size(min=2, max=64) - private String facilityId = null; + private List facilityId = null; @JsonProperty("productVariantId") - @Size(min=2, max=64) - private String productVariantId = null; + private List productVariantId = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearchRequest.java index 66d89a4efbd..6b307ce2d11 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearchRequest.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * StockReconciliationSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockRequest.java index 8e2e6b1d9fa..10b7f7fde07 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockRequest.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * StockRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockResponse.java index ef0504b3098..1cea9fc0185 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockResponse.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * StockResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearch.java index 29564b1605e..5e03a4daaf1 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearch.java @@ -1,49 +1,43 @@ package org.egov.common.models.stock; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Size; -import java.util.List; - /** * StockSearch */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class StockSearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; +public class StockSearch extends EgovOfflineSearchModel { @JsonProperty("facilityId") @Size(min=2, max=64) private String facilityId = null; @JsonProperty("productVariantId") - @Size(min=2, max=64) - private String productVariantId = null; + private List productVariantId = null; @JsonProperty("referenceId") private String referenceId = null; @JsonProperty("wayBillNumber") - private String wayBillNumber = null; + private List wayBillNumber = null; @JsonProperty("referenceIdType") @Size(min=2, max=64) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearchRequest.java index 3a072809362..9f73cb1e00e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearchRequest.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * StockSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/TenantRole.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/TenantRole.java index e95bbfa9560..261bcb9d725 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/TenantRole.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/TenantRole.java @@ -9,8 +9,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ */ @ApiModel(description = "User role carries the tenant related role information for the user. A user can have multiple roles per tenant based on the need of the tenant. A user may also have multiple roles for multiple tenants.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/UserInfo.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/UserInfo.java index 2b8b0fb9b52..85edeeef0aa 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/UserInfo.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/UserInfo.java @@ -9,8 +9,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ */ @ApiModel(description = "This is acting ID token of the authenticated user on the server. Any value provided by the clients will be ignored and actual user based on authtoken will be used on the server.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/transformer/upstream/Boundary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/transformer/upstream/Boundary.java deleted file mode 100644 index cf23efe5f82..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/transformer/upstream/Boundary.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.egov.common.models.transformer.upstream; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - -/** -* Boundary -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class Boundary { - - @JsonProperty("code") - @NotNull - private String code = null; - - @JsonProperty("name") - private String name = null; - - @JsonProperty("label") - private String label = null; - - @JsonProperty("latitude") - private String latitude = null; - - @JsonProperty("longitude") - private String longitude = null; - - @JsonProperty("children") - @Valid - private List children = null; - - @JsonProperty("materializedPath") - private String materializedPath = null; - - public Boundary addChildrenItem(Boundary childrenItem) { - if (this.children == null) { - this.children = new ArrayList<>(); - } - this.children.add(childrenItem); - return this; - } - -} - diff --git a/health-services/plan-service/CHANGELOG.md b/health-services/plan-service/CHANGELOG.md new file mode 100644 index 00000000000..650d79eae57 --- /dev/null +++ b/health-services/plan-service/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog +All notable changes to this module will be documented in this file. + +## 1.0.0 - 2024-06-24 +#### Plan Service + 1. Plan Service manages: validation of plans, plan search, plan create, plan update. + 2. Validation of plan: Plan service validates plan request before it takes action on it like update or create. + 3. Plan Create: Plan service creates a plan after successful validation is done. It sends create request on topic to create plan. + 4. Plan Update : Plan service creates a plan after successful validation is done. It sends update request on topic to resource estimation service to further process. + 5. Plan Search: This enables to search plan based on provided search string. \ No newline at end of file diff --git a/health-services/plan-service/LOCALSETUP.md b/health-services/plan-service/LOCALSETUP.md new file mode 100644 index 00000000000..b1a80932b83 --- /dev/null +++ b/health-services/plan-service/LOCALSETUP.md @@ -0,0 +1,40 @@ +# Local Setup + +To set up the Plan Service in your local system, clone the [Health Campaign Services repository](https://github.com/egovernments/health-campaign-services.git). + +## Dependencies + +- [x] Postgres DB +- [ ] Redis +- [ ] Elasticsearch +- [x] Kafka + - [x] Consumer + - [x] Producer + + +## Running Locally + +### Local setup +1. To set up the Plan Service in your local system, clone the [Health Campaign Services repository](https://github.com/egovernments/health-campaign-services.git). +2. Install GIT. + [For Windows](https://git-scm.com/download/win). + [For Linux](https://www.digitalocean.com/community/tutorials/how-to-install-git-on-ubuntu-18-04-quickstart). +2. Install JDK version 17 or above. + [For windows](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html). + [For Linux](https://javahelps.com/install-oracle-jdk-17-on-linux). +3. Install maven locally and configure environment variables. +4. Install Kafka (version 3.2.0 which is the latest version) - To install and run Kafka locally, follow the following links - + [Kafka for windows](https://dzone.com/articles/running-apache-kafka-on-windows-os) or [Kafka for Linux](https://tecadmin.net/install-apache-kafka-ubuntu/) +5. Install Postman - To install Postman, follow the following links - + [Postman for windows](https://www.postman.com/downloads/) +6. Install Kubectl - Kubectl is the tool that we use to interact with services deployed on our sandbox environment - + [kubectl for windows](https://core.digit.org/guides/operations-guide/working-with-kubernetes/installation-of-kubectl) + [kubectl for Linux](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/) +7. Install aws-iam-authenticator - [if the DIGIT development environment is in AWS](https://docs.aws.amazon.com/eks/latest/userguide/install-aws-iam-authenticator.html) +8. Install PostgreSQL v14 locally. +9. Also update DB config values as per your local system config. +10. Update the host settings for all dependency services, either on any unified environment or by port-forwarding. +11. Run spring boot main class + +> Note: After running the above, if a Kafka error occurs, ensure that Kafka and Zookeeper are running in the background. If a connection error with another microservice occurs, ensure that the URL mentioned in the external mapping of the data config is correct, or you can port-forward that particular service. +\ No newline at end of file \ No newline at end of file diff --git a/health-services/plan-service/README.md b/health-services/plan-service/README.md new file mode 100644 index 00000000000..0b940dd90f7 --- /dev/null +++ b/health-services/plan-service/README.md @@ -0,0 +1,58 @@ +# Plan Service Documentation + +## Overview + +The PlanService is a tool designed for managing plan configurations and microplans. It supports various functionalities such as creating, updating, validating, and processing plan configurations, microplans, and related elements. This service can operate independently for micro planning or integrate with DIGIT HCM for campaign execution and monitoring. + +## Key Features + +- **Data Upload for Microplanning**: Upload essential data in formats including .xlsx (Excel), Shapefiles, and GeoJSON. +- **Assumptions Configuration**: Configure assumptions crucial for estimation processes. +- **Formula Configuration**: Set up formulae to calculate estimated resources (e.g., human resources, commodities, budgets). +- **Visualization**: Visualize microplans on a map layer using GIS technologies. +- **Output Generation**: Generate, save, and print microplans. + +## Service Dependencies + +- **Mdms-service**: Dependency for managing Master Data Management System. + +## API Documentation + +- **Swagger Link**: [Plan Service Swagger](https://editor.swagger.io/?url=https://raw.githubusercontent.com/egovernments/DIGIT-Specs/grouped-service-contracts/Domain%20Services/Plan%20Service/plan-1.0.0.yaml) + +## Database and Persistence + +- **DB Diagrams**: Detailed diagrams for Microplan and Plan Configuration are available. + +## Configuration and Deployment + +- **Persister Config**: Configuration for persistence can be found in [plan-service-persister.yml](https://github.com/egovernments/configs/blob/UNIFIED-QA/health/egov-persister/plan-service-persister.yml). +- **Helm Chart**: Deployment details available in the [Helm chart](https://github.com/egovernments/DIGIT-DevOps/tree/unified-env/deploy-as-code/helm/charts/health-services/plan-service). + +## Role and Access Control + +- **Access Control Role**: Configure the role `MICROPLAN_ADMIN` in the ‘ACCESSCONTROL-ROLES’ module. +- **Role-Action Mapping**: Map actions to role codes in the ‘ACCESSCONTROL-ROLEACTIONS’ module as per the provided mappings. + +### Role-Action Mappings (Dev Environment) + +- `/plan-service/plan/_create`: `MICROPLAN_ADMIN` +- `/plan-service/plan/_search`: `MICROPLAN_ADMIN` +- `/plan-service/plan/_update`: `MICROPLAN_ADMIN` +- `/plan-service/config/_create`: `MICROPLAN_ADMIN` +- `/plan-service/config/_search`: `MICROPLAN_ADMIN` +- `/plan-service/config/_update`: `MICROPLAN_ADMIN` + +## Environment Variables + +- Configure environment variables such as `db-host`, `db-name`, `db-url`, `domain`, and other DIGIT core platform services configurations before deployment. Example configurations can be found in the [unified-qa.yaml](https://github.com/egovernments/DIGIT-DevOps/blob/unified-env/deploy-as-code/helm/environments/unified-qa.yaml). + +## MDMS Configuration + +- Configure MDMS data for Plan Service including UOM config, Metric config, Assumptions config, Input rules, Output rules, Campaign Based Schema, Microplan status, Map layers, Map filters, Preview Aggregates, and UI configs. Reference data can be found [here](https://github.com/egovernments/egov-mdms-data/tree/UNIFIED-QA/data/mz/health/hcm-microplanning). + +## Reference Documents + +- **MDMS Technical Document**: [Mdms service](https://core.digit.org/platform/core-services/mdms-master-data-management-service) +- **Persister Technical Document**: [Persister service](https://core.digit.org/platform/core-services/persister-service) +- **API Contract**: [API Contract](https://github.com/egovernments/SANITATION/blob/develop/API-CONTRACTS/pqm/PQM_API_ANOMALY_Contract.yaml) diff --git a/health-services/plan-service/pom.xml b/health-services/plan-service/pom.xml new file mode 100644 index 00000000000..ce6a2dff717 --- /dev/null +++ b/health-services/plan-service/pom.xml @@ -0,0 +1,115 @@ + + 4.0.0 + org.egov + plan-service + jar + plan-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 + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.flywaydb + flyway-core + 9.22.3 + + + org.postgresql + postgresql + 42.7.1 + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-validation + + + io.swagger + swagger-core + 1.5.18 + + + io.swagger.core.v3 + swagger-annotations + 2.2.8 + + + + 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 + + + junit + junit + test + + + + + 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/plan-service/src/main/java/digit/Main.java b/health-services/plan-service/src/main/java/digit/Main.java new file mode 100644 index 00000000000..9ccda08d54e --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/Main.java @@ -0,0 +1,19 @@ +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/plan-service/src/main/java/digit/config/Configuration.java b/health-services/plan-service/src/main/java/digit/config/Configuration.java new file mode 100644 index 00000000000..7cf4b3549f7 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/config/Configuration.java @@ -0,0 +1,51 @@ +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; + +@Component +@Data +@Import({TracerConfiguration.class}) +@NoArgsConstructor +@AllArgsConstructor +@Setter +@Getter +public class Configuration { + + //MDMS + @Value("${egov.mdms.host}") + private String mdmsHost; + + @Value("${egov.mdms.search.endpoint}") + private String mdmsEndPoint; + + + //Persister Topic + @Value("${plan.configuration.create.topic}") + private String planConfigCreateTopic; + + @Value("${plan.configuration.update.topic}") + private String planConfigUpdateTopic; + + @Value("${plan.create.topic}") + private String planCreateTopic; + + @Value("${plan.update.topic}") + private String planUpdateTopic; + + @Value("${plan.default.offset}") + private Integer defaultOffset; + + @Value("${plan.default.limit}") + private Integer defaultLimit; + +} diff --git a/health-services/plan-service/src/main/java/digit/config/MainConfiguration.java b/health-services/plan-service/src/main/java/digit/config/MainConfiguration.java new file mode 100644 index 00000000000..ea9816c9be0 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/config/MainConfiguration.java @@ -0,0 +1,46 @@ +package digit.config; + +import jakarta.annotation.PostConstruct; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import java.util.TimeZone; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.jdbc.core.SingleColumnRowMapper; + + +@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; + } + + @Bean + public SingleColumnRowMapper singleColumnRowMapper() { + return new SingleColumnRowMapper<>(String.class); + } + +} \ No newline at end of file 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 new file mode 100644 index 00000000000..2266c82de93 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/config/ServiceConstants.java @@ -0,0 +1,113 @@ +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 ERROR_WHILE_FETCHING_FROM_MDMS = "Exception occurred while fetching category lists from mdms: "; + + public static final String RES_MSG_ID = "uief87324"; + public static final String SUCCESSFUL = "successful"; + public static final String FAILED = "failed"; + + 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_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 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"; + + public static final String REQUIRED_TEMPLATE_IDENTIFIER_NOT_FOUND_CODE = "REQUIRED_TEMPLATE_IDENTIFIER_NOT_FOUND"; + public static final String REQUIRED_TEMPLATE_IDENTIFIER_NOT_FOUND_MESSAGE = "Required Template Identifier is not present in Files"; + + public static final String ONLY_ONE_FILE_OF_REQUIRED_TEMPLATE_IDENTIFIER_CODE = "ONLY_ONE_FILE_OF_REQUIRED_TEMPLATE_IDENTIFIER"; + 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 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 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 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 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"; + + public static final String METRIC_UNIT_NOT_FOUND_IN_MDMS_CODE = "METRIC_UNIT_NOT_FOUND_IN_MDMS"; + public static final String METRIC_UNIT_NOT_FOUND_IN_MDMS_MESSAGE = "Metric Details' Unit not found in MDMS"; + + public static final String INACTIVE_OPERATION_USED_AS_INPUT_CODE = "INACTIVE_OPERATION_USED_AS_INPUT"; + public static final String INACTIVE_OPERATION_USED_AS_INPUT_MESSAGE = "Inactive operation output used. "; + + 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."; + + //mdms constants + public static final String MDMS_PLAN_MODULE_NAME = "hcm-microplanning"; + 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"; + public static final String MDMS_MASTER_SCHEMAS = "Schemas"; + public static final String MDMS_MASTER_METRIC = "Metric"; + public static final String MDMS_MASTER_UOM = "Uom"; + + public static final String DOT_SEPARATOR = "."; + + public static final String DOT_REGEX = "\\."; + + public static final String FILTER_CODE = "$.*.code"; + + public static final String FILTER_ID = "$.*.id"; + + public static final String FILTER_DATA = "$.*.data"; + + public static final String LOCALITY_CODE = "Locality"; + + public static final String MDMS_SCHEMA_SECTION = "section"; + + public static final String MDMS_SCHEMA_TYPE = "type"; + + public static final String MDMS_SCHEMA_SCHEMA = "schema"; + + public static final String MDMS_SCHEMA_PROPERTIES = "Properties"; + + 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 BOUNDARY_CODE = "boundaryCode"; + +} diff --git a/health-services/plan-service/src/main/java/digit/kafka/Producer.java b/health-services/plan-service/src/main/java/digit/kafka/Producer.java new file mode 100644 index 00000000000..542f4f686c0 --- /dev/null +++ b/health-services/plan-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/plan-service/src/main/java/digit/kafka/ResourceEstimationConsumer.java b/health-services/plan-service/src/main/java/digit/kafka/ResourceEstimationConsumer.java new file mode 100644 index 00000000000..c6688cc70d8 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/kafka/ResourceEstimationConsumer.java @@ -0,0 +1,38 @@ +package digit.kafka; + +import java.util.Map; + +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 com.fasterxml.jackson.databind.ObjectMapper; + +import digit.service.PlanService; +import digit.web.models.PlanRequest; +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class ResourceEstimationConsumer { + + private ObjectMapper objectMapper; + + private PlanService planService; + + public ResourceEstimationConsumer(ObjectMapper objectMapper, PlanService planService) { + this.objectMapper = objectMapper; + this.planService = planService; + } + + @KafkaListener(topics = {"${resource.config.consumer.plan.create.topic}"}) + public void listen(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + PlanRequest planRequest = objectMapper.convertValue(consumerRecord, PlanRequest.class); + planService.createPlan(planRequest); + } catch (Exception exception) { + log.error("Error in plan consumer", exception); + } + } +} 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 new file mode 100644 index 00000000000..ca72bb21058 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/kafka/UpdatePlanConfigConsumer.java @@ -0,0 +1,36 @@ +package digit.kafka; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.service.PlanConfigurationService; +import digit.web.models.PlanConfigurationRequest; +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 UpdatePlanConfigConsumer { + + private PlanConfigurationService planConfigurationService; + + private ObjectMapper objectMapper; + + public UpdatePlanConfigConsumer(PlanConfigurationService planConfigurationService, ObjectMapper objectMapper) { + this.planConfigurationService = planConfigurationService; + this.objectMapper = objectMapper; + } + + @KafkaListener(topics = {"${resource.update.plan.config.consumer.topic}"}) + public void listen(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + PlanConfigurationRequest planConfigurationRequest = objectMapper.convertValue(consumerRecord, PlanConfigurationRequest.class); + 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/PlanConfigurationRepository.java b/health-services/plan-service/src/main/java/digit/repository/PlanConfigurationRepository.java new file mode 100644 index 00000000000..49efc1d89f4 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/PlanConfigurationRepository.java @@ -0,0 +1,20 @@ +package digit.repository; + + +import digit.web.models.PlanConfiguration; +import digit.web.models.PlanConfigurationRequest; +import digit.web.models.PlanConfigurationSearchCriteria; +import java.util.List; +import org.springframework.stereotype.Repository; + + +public interface PlanConfigurationRepository { + + public void create(PlanConfigurationRequest planConfigurationRequest); + + public List search(PlanConfigurationSearchCriteria planConfigurationSearchCriteria); + + public void update(PlanConfigurationRequest planConfigurationRequest); + + +} 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 new file mode 100644 index 00000000000..eb76b357701 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/PlanRepository.java @@ -0,0 +1,16 @@ +package digit.repository; + +import digit.web.models.Plan; +import digit.web.models.PlanRequest; +import digit.web.models.PlanSearchCriteria; + +import java.util.List; + +public interface PlanRepository { + public void create(PlanRequest planRequest); + + public List search(PlanSearchCriteria planSearchCriteria); + + public void update(PlanRequest planRequest); + +} 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 new file mode 100644 index 00000000000..d09d230e4fa --- /dev/null +++ b/health-services/plan-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/plan-service/src/main/java/digit/repository/impl/PlanConfigurationRepositoryImpl.java b/health-services/plan-service/src/main/java/digit/repository/impl/PlanConfigurationRepositoryImpl.java new file mode 100644 index 00000000000..7ad1ed8e995 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/impl/PlanConfigurationRepositoryImpl.java @@ -0,0 +1,124 @@ +package digit.repository.impl; + +import digit.config.Configuration; +import digit.kafka.Producer; +import digit.repository.PlanConfigurationRepository; +import digit.repository.querybuilder.PlanConfigQueryBuilder; +import digit.repository.rowmapper.PlanConfigRowMapper; +import digit.util.ResponseInfoFactory; +import digit.web.models.PlanConfiguration; +import digit.web.models.PlanConfigurationRequest; +import digit.web.models.PlanConfigurationSearchCriteria; +import java.util.ArrayList; +import java.util.List; +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; + +@Repository +@Slf4j +public class PlanConfigurationRepositoryImpl implements PlanConfigurationRepository { + + private Producer producer; + + private JdbcTemplate jdbcTemplate; + + private Configuration config; + + private PlanConfigQueryBuilder planConfigQueryBuilder; + + private PlanConfigRowMapper planConfigRowMapper; + + public PlanConfigurationRepositoryImpl(Producer producer, JdbcTemplate jdbcTemplate, + Configuration config, PlanConfigQueryBuilder planConfigQueryBuilder, PlanConfigRowMapper planConfigRowMapper) { + this.producer = producer; + this.jdbcTemplate = jdbcTemplate; + this.config = config; + this.planConfigQueryBuilder = planConfigQueryBuilder; + this.planConfigRowMapper = planConfigRowMapper; + } + + /** + * Pushes a new plan configuration to persister kafka topic. + * @param planConfigurationRequest The request containing the plan configuration details. + */ + @Override + public void create(PlanConfigurationRequest planConfigurationRequest) { + producer.push(config.getPlanConfigCreateTopic(), planConfigurationRequest); + } + + /** + * Searches for plan configurations based on the provided search criteria. + * @param planConfigurationSearchCriteria The criteria to use for searching plan configurations. + * @return A list of plan configurations that match the search criteria. + */ + @Override + public List search(PlanConfigurationSearchCriteria planConfigurationSearchCriteria) { + // Fetch plan ids from database + List planConfigIds = queryDatabaseForPlanConfigIds(planConfigurationSearchCriteria); + + // Return empty list back as response if no plan ids are found + if(CollectionUtils.isEmpty(planConfigIds)) { + log.info("No plan config ids found for provided plan configuration search criteria."); + return new ArrayList<>(); + } + + List planConfigurations = searchPlanConfigsByIds(planConfigIds); + return planConfigurations; + } + + /** + * Counts the number of plan configurations based on the provided search criteria. + * + * @param planConfigurationSearchCriteria The search criteria for filtering plan configurations. + * @return The total count of plan configurations matching the search criteria. + */ + public Integer count(PlanConfigurationSearchCriteria planConfigurationSearchCriteria) { + List preparedStmtList = new ArrayList<>(); + String query = planConfigQueryBuilder.getPlanConfigCountQuery(planConfigurationSearchCriteria, preparedStmtList); + + log.info("Plan Config count query: " + query); + log.info("preparedStmtList: " + preparedStmtList); + + Integer count = jdbcTemplate.queryForObject(query, preparedStmtList.toArray(), Integer.class); + log.info("Total plan config count is : " + count); + + return count; + } + + /** + * Pushes an updated existing plan configuration to persister kafka topic. + * @param planConfigurationRequest The request containing the updated plan configuration details. + */ + @Override + public void update(PlanConfigurationRequest planConfigurationRequest) { + producer.push(config.getPlanConfigUpdateTopic(), planConfigurationRequest); + } + + /** + * Helper method to query database for plan ids based on the provided search criteria. + * @param planConfigurationSearchCriteria + * @return + */ + private List queryDatabaseForPlanConfigIds(PlanConfigurationSearchCriteria planConfigurationSearchCriteria) { + List preparedStmtList = new ArrayList<>(); + String query = planConfigQueryBuilder.getPlanConfigSearchQuery(planConfigurationSearchCriteria, preparedStmtList); + log.info("Plan Config search query: " + query); + return jdbcTemplate.query(query, new SingleColumnRowMapper<>(String.class), preparedStmtList.toArray()); + } + + /** + * Helper method to search for plan configs based on the provided plan config ids. + * @param planConfigIds + * @return + */ + private List searchPlanConfigsByIds(List planConfigIds) { + List preparedStmtList = new ArrayList<>(); + String query = planConfigQueryBuilder.getPlanConfigQuery(planConfigIds, preparedStmtList); + log.info("Plan Config query: " + query); + return jdbcTemplate.query(query, planConfigRowMapper, 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 new file mode 100644 index 00000000000..c6acbb55221 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/impl/PlanRepositoryImpl.java @@ -0,0 +1,115 @@ +package digit.repository.impl; + +import digit.config.Configuration; +import digit.kafka.Producer; +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 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 java.util.ArrayList; +import java.util.List; + +@Slf4j +@Repository +public class PlanRepositoryImpl implements PlanRepository { + + private Producer producer; + + private PlanQueryBuilder planQueryBuilder; + + private PlanRowMapper planRowMapper; + + private JdbcTemplate jdbcTemplate; + + private Configuration config; + + public PlanRepositoryImpl(Producer producer, PlanQueryBuilder planQueryBuilder, PlanRowMapper planRowMapper, + JdbcTemplate jdbcTemplate, Configuration config) { + this.producer = producer; + this.planQueryBuilder = planQueryBuilder; + this.planRowMapper = planRowMapper; + this.jdbcTemplate = jdbcTemplate; + this.config = config; + } + + /** + * This method emits an event to the persister for it to save the plan in the database. + * @param planRequest + */ + @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); + } + } + + /** + * This method searches for plans based on the search criteria. + * @param planSearchCriteria + * @return + */ + @Override + public List search(PlanSearchCriteria planSearchCriteria) { + // Fetch plan ids from database + List planIds = queryDatabaseForPlanIds(planSearchCriteria); + + // Return empty list back as response if no plan ids are found + if(CollectionUtils.isEmpty(planIds)) { + log.info("No plan ids found for provided plan search criteria."); + return new ArrayList<>(); + } + + // Fetch plans from database based on the acquired ids + List plans = searchPlanByIds(planIds); + + return plans; + } + + /** + * This method emits an event to the persister for it to update the plan in the database. + * @param planRequest + */ + @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); + } + } + + /** + * Helper method to query database for plan ids based on the provided search criteria. + * @param planSearchCriteria + * @return + */ + private List queryDatabaseForPlanIds(PlanSearchCriteria planSearchCriteria) { + List preparedStmtList = new ArrayList<>(); + String query = planQueryBuilder.getPlanSearchQuery(planSearchCriteria, preparedStmtList); + log.info("Plan search query: " + query); + return jdbcTemplate.query(query, new SingleColumnRowMapper<>(String.class), preparedStmtList.toArray()); + } + + /** + * Helper method to search for plans based on the provided plan ids. + * @param planIds + * @return + */ + private List searchPlanByIds(List planIds) { + List preparedStmtList = new ArrayList<>(); + String query = planQueryBuilder.getPlanQuery(planIds, preparedStmtList); + log.info("Plan query: " + query); + return jdbcTemplate.query(query, planRowMapper, preparedStmtList.toArray()); + } + +} 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 new file mode 100644 index 00000000000..6dc4449b55f --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanConfigQueryBuilder.java @@ -0,0 +1,186 @@ +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; + +@Component +public class PlanConfigQueryBuilder { + + private Configuration config; + + public PlanConfigQueryBuilder(Configuration config) { + this.config = config; + } + + 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" + + "\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 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" + + "\t LEFT JOIN plan_configuration_assumptions pca ON pc.id = pca.plan_configuration_id\n" + + "\t LEFT JOIN plan_configuration_operations pco ON pc.id = pco.plan_configuration_id\n" + + "\t LEFT JOIN plan_configuration_mapping pcm ON pc.id = pcm.plan_configuration_id"; + + private static final String PLAN_CONFIG_SEARCH_QUERY_ORDER_BY_CLAUSE = " ORDER BY pc.last_modified_time DESC"; + + private static final String PLAN_CONFIG_SEARCH_QUERY_COUNT_WRAPPER = "SELECT COUNT(*) AS total_count FROM ( "; + + public String getPlanConfigQuery(List ids, List preparedStmtList) { + return buildPlanConfigQuery(ids, preparedStmtList); + } + + private String buildPlanConfigQuery(List ids, List preparedStmtList) { + 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)); + } + + addActiveWhereClause(builder, preparedStmtList); + + return QueryUtil.addOrderByClause(builder.toString(), PLAN_CONFIG_SEARCH_QUERY_ORDER_BY_CLAUSE); + } + + /** + * Constructs a SQL query string for searching PlanConfiguration objects based on the provided search criteria. + * Also adds an ORDER BY clause and handles pagination. + * + * @param criteria The criteria used for filtering PlanConfiguration objects. + * @param preparedStmtList A list to store prepared statement parameters. + * @return A complete SQL query string for searching PlanConfiguration objects. + */ + 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 = getPaginatedQuery(query, criteria, preparedStmtList); + + return query; + } + + public String getPlanConfigCountQuery(PlanConfigurationSearchCriteria criteria, List preparedStmtList) { + String query = buildPlanConfigSearchQuery(criteria, preparedStmtList, Boolean.TRUE); + return query; + } + + /** + * Constructs query based on the provided search criteria + * + * @param criteria The criteria used for filtering PlanConfiguration objects. + * @param preparedStmtList A list to store prepared statement parameters. + * @return + */ + private String buildPlanConfigSearchQuery(PlanConfigurationSearchCriteria criteria, List preparedStmtList, Boolean isCount) { + StringBuilder builder = new StringBuilder(PLAN_CONFIG_SEARCH_BASE_QUERY); + + if (criteria.getTenantId() != null) { + addClauseIfRequired(preparedStmtList, builder); + builder.append(" pc.tenant_id = ?"); + preparedStmtList.add(criteria.getTenantId()); + } + + if (criteria.getId() != null) { + addClauseIfRequired(preparedStmtList, builder); + builder.append(" pc.id = ?"); + preparedStmtList.add(criteria.getId()); + } + + if (criteria.getExecutionPlanId() != null) { + addClauseIfRequired(preparedStmtList, builder); + builder.append(" pc.execution_plan_id = ?"); + preparedStmtList.add(criteria.getExecutionPlanId()); + } + + if (criteria.getName() != null) { + addClauseIfRequired(preparedStmtList, builder); + builder.append(" pc.name = ?"); + preparedStmtList.add(criteria.getName()); + } + + if (criteria.getStatus() != null) { + addClauseIfRequired(preparedStmtList, builder); + builder.append(" pc.status = ?"); + preparedStmtList.add(criteria.getStatus()); + } + + if (criteria.getUserUuid() != null) { + addClauseIfRequired(preparedStmtList, builder); + builder.append(" pc.created_by = ?"); + preparedStmtList.add(criteria.getUserUuid()); + } + + StringBuilder countQuery = new StringBuilder(); + if (isCount) { + + countQuery.append(PLAN_CONFIG_SEARCH_QUERY_COUNT_WRAPPER).append(builder); + + countQuery.append(") AS subquery"); + + return countQuery.toString(); + } + + return builder.toString(); + } + + private void addClauseIfRequired(List preparedStmtList, StringBuilder queryString) { + if (preparedStmtList.isEmpty()) { + queryString.append(" WHERE "); + } else { + queryString.append(" AND"); + } + } + + /** + * @param query prepared Query + * @param planConfigurationSearchCriteria plan config search criteria + * @param preparedStmtList values to be replaced on the query + * @return the query by replacing the placeholders with preparedStmtList + */ + private String getPaginatedQuery(String query, PlanConfigurationSearchCriteria planConfigurationSearchCriteria, List preparedStmtList) { + StringBuilder paginatedQuery = new StringBuilder(query); + + // Append offset + paginatedQuery.append(" OFFSET ? "); + preparedStmtList.add(ObjectUtils.isEmpty(planConfigurationSearchCriteria.getOffset()) ? config.getDefaultOffset() : planConfigurationSearchCriteria.getOffset()); + + // Append limit + paginatedQuery.append(" LIMIT ? "); + preparedStmtList.add(ObjectUtils.isEmpty(planConfigurationSearchCriteria.getLimit()) ? config.getDefaultLimit() : planConfigurationSearchCriteria.getLimit()); + + return paginatedQuery.toString(); + } + + public void addActiveWhereClause(StringBuilder builder, List preparedStmtList) + { + addClauseIfRequired(preparedStmtList, builder); + builder.append(" pcf.active = ?"); + preparedStmtList.add(Boolean.TRUE); + + addClauseIfRequired(preparedStmtList, builder); + builder.append(" pca.active = ?"); + preparedStmtList.add(Boolean.TRUE); + + addClauseIfRequired(preparedStmtList, builder); + builder.append(" pco.active = ?"); + preparedStmtList.add(Boolean.TRUE); + + addClauseIfRequired(preparedStmtList, builder); + builder.append(" pcm.active = ?"); + preparedStmtList.add(Boolean.TRUE); + } + + +} + 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 new file mode 100644 index 00000000000..1b0adb59213 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanQueryBuilder.java @@ -0,0 +1,115 @@ +package digit.repository.querybuilder; + +import digit.config.Configuration; +import digit.util.QueryUtil; +import digit.web.models.PlanSearchCriteria; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import java.util.LinkedHashSet; +import java.util.List; + +@Component +public class PlanQueryBuilder { + + private Configuration config; + + public PlanQueryBuilder(Configuration config) { + this.config = config; + } + + 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" + + "\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" + + "\t plan_target.id as plan_target_id, plan_target.metric as plan_target_metric, plan_target.metric_value as plan_target_metric_value, plan_target.metric_comparator as plan_target_metric_comparator, plan_target.metric_unit as plan_target_metric_unit, plan_target.plan_id as plan_target_plan_id, plan_target.activity_code as plan_target_activity_code, plan_target.created_by as plan_target_created_by, plan_target.created_time as plan_target_created_time, plan_target.last_modified_by as plan_target_last_modified_by, plan_target.last_modified_time as plan_target_last_modified_time\n" + + "\t FROM plan \n" + + "\t LEFT JOIN plan_activity ON plan.id = plan_activity.plan_id\n" + + "\t LEFT JOIN plan_activity_condition ON plan_activity.id = plan_activity_condition.activity_id\n" + + "\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 PLAN_SEARCH_QUERY_ORDER_BY_CLAUSE = " order by plan.last_modified_time desc "; + + public String getPlanQuery(List ids, List preparedStmtList) { + return buildPlanQuery(ids, preparedStmtList); + } + + 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)); + } + + return builder.toString(); + } + + public String getPlanSearchQuery(PlanSearchCriteria planSearchCriteria, List preparedStmtList) { + String query = buildPlanSearchQuery(planSearchCriteria, preparedStmtList); + query = QueryUtil.addOrderByClause(query, PLAN_SEARCH_QUERY_ORDER_BY_CLAUSE); + query = getPaginatedQuery(query, planSearchCriteria, preparedStmtList); + return query; + } + + /** + * 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) { + StringBuilder builder = new StringBuilder(PLAN_SEARCH_BASE_QUERY); + + if (!ObjectUtils.isEmpty(planSearchCriteria.getTenantId())) { + 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()); + } + + if (!ObjectUtils.isEmpty(planSearchCriteria.getLocality())) { + QueryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" locality = ? "); + preparedStmtList.add(planSearchCriteria.getLocality()); + } + + if (!ObjectUtils.isEmpty(planSearchCriteria.getExecutionPlanId())) { + QueryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" execution_plan_id = ? "); + preparedStmtList.add(planSearchCriteria.getExecutionPlanId()); + } + + if (!ObjectUtils.isEmpty(planSearchCriteria.getPlanConfigurationId())) { + QueryUtil.addClauseIfRequired(builder, preparedStmtList); + builder.append(" plan_configuration_id = ? "); + preparedStmtList.add(planSearchCriteria.getPlanConfigurationId()); + } + + return builder.toString(); + } + + private String getPaginatedQuery(String query, PlanSearchCriteria planSearchCriteria, List preparedStmtList) { + StringBuilder paginatedQuery = new StringBuilder(query); + + // Append offset + paginatedQuery.append(" OFFSET ? "); + preparedStmtList.add(ObjectUtils.isEmpty(planSearchCriteria.getOffset()) ? config.getDefaultOffset() : planSearchCriteria.getOffset()); + + // Append limit + paginatedQuery.append(" LIMIT ? "); + preparedStmtList.add(ObjectUtils.isEmpty(planSearchCriteria.getLimit()) ? config.getDefaultLimit() : planSearchCriteria.getLimit()); + + return paginatedQuery.toString(); + } + +} 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 new file mode 100644 index 00000000000..f8aebd12a9a --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanConfigRowMapper.java @@ -0,0 +1,195 @@ +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 org.egov.common.contract.models.AuditDetails; +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; + +@Component +public class PlanConfigRowMapper implements ResultSetExtractor> { + + @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<>(); + + + while (rs.next()) { + String planConfigId = rs.getString("plan_configuration_id"); + + PlanConfiguration planConfigEntry = planConfigurationMap.get(planConfigId); + + if (ObjectUtils.isEmpty(planConfigEntry)) { + planConfigEntry = new PlanConfiguration(); + + // 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(); + + // Prepare plan object + 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.setAuditDetails(auditDetails); + + } + addFiles(rs, planConfigEntry, fileMap); + addAssumptions(rs, planConfigEntry, assumptionMap); + addOperations(rs, planConfigEntry, operationMap); + addResourceMappings(rs, planConfigEntry, resourceMappingMap); + + planConfigurationMap.put(planConfigId, planConfigEntry); + } + return new ArrayList<>(planConfigurationMap.values()); + } + + /** + * Adds a File object to the PlanConfiguration entry based on the result set. + * + * @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. + * @throws SQLException If an SQL error occurs. + */ + private void addFiles(ResultSet rs, PlanConfiguration planConfigEntry, Map fileMap) throws SQLException { + String fileId = rs.getString("plan_configuration_files_id"); + + if (ObjectUtils.isEmpty(fileId) || fileMap.containsKey(fileId)) { + return; + } + + File file = new File(); + file.setId(fileId); + file.setFilestoreId(rs.getString("plan_configuration_files_filestore_id")); + file.setInputFileType(File.InputFileTypeEnum.valueOf(rs.getString("plan_configuration_files_input_file_type").toUpperCase())); + file.setTemplateIdentifier(rs.getString("plan_configuration_files_template_identifier")); + file.setActive(rs.getBoolean("plan_configuration_files_active")); + if (CollectionUtils.isEmpty(planConfigEntry.getFiles())) { + List fileList = new ArrayList<>(); + fileList.add(file); + planConfigEntry.setFiles(fileList); + } else { + planConfigEntry.getFiles().add(file); + } + + fileMap.put(fileId, file); + } + + + /** + * Adds an Assumption object to the PlanConfiguration entry based on the result set. + * + * @param rs The ResultSet containing the data. + * @param planConfigEntry The PlanConfiguration entry to which the Assumption object will be added. + * @param assumptionMap A map to keep track of added Assumption objects. + * @throws SQLException If an SQL error occurs. + */ + private void addAssumptions(ResultSet rs, PlanConfiguration planConfigEntry, Map assumptionMap) throws SQLException { + String assumptionId = rs.getString("plan_configuration_assumptions_id"); + + if (ObjectUtils.isEmpty(assumptionId) || assumptionMap.containsKey(assumptionId)) { + return; + } + + Assumption assumption = new Assumption(); + assumption.setId(assumptionId); + assumption.setKey(rs.getString("plan_configuration_assumptions_key")); + assumption.setValue(rs.getBigDecimal("plan_configuration_assumptions_value")); + assumption.setActive(rs.getBoolean("plan_configuration_assumptions_active")); + + if (CollectionUtils.isEmpty(planConfigEntry.getAssumptions())) { + List assumptionList = new ArrayList<>(); + assumptionList.add(assumption); + planConfigEntry.setAssumptions(assumptionList); + } else { + planConfigEntry.getAssumptions().add(assumption); + } + + assumptionMap.put(assumptionId, assumption); + } + + /** + * Adds an Operation object to the PlanConfiguration entry based on the result set. + * + * @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. + * @throws SQLException If an SQL error occurs. + */ + private void addOperations(ResultSet rs, PlanConfiguration planConfigEntry, Map operationMap) throws SQLException { + String operationId = rs.getString("plan_configuration_operations_id"); + + if (ObjectUtils.isEmpty(operationId) || operationMap.containsKey(operationId)) { + return; + } + + Operation operation = new Operation(); + operation.setId(operationId); + operation.setInput(rs.getString("plan_configuration_operations_input")); + operation.setOperator(Operation.OperatorEnum.fromValue(rs.getString("plan_configuration_operations_operator"))); + 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")); + + if (CollectionUtils.isEmpty(planConfigEntry.getOperations())) { + List operationList = new ArrayList<>(); + operationList.add(operation); + planConfigEntry.setOperations(operationList); + } else { + planConfigEntry.getOperations().add(operation); + } + + operationMap.put(operationId, operation); + } + + /** + * Adds a ResourceMapping object to the PlanConfiguration entry based on the result set. + * + * @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. + * @throws SQLException If an SQL error occurs. + */ + private void addResourceMappings(ResultSet rs, PlanConfiguration planConfigEntry, Map mappingMap) throws SQLException { + String mappingId = rs.getString("plan_configuration_mapping_id"); + + if (ObjectUtils.isEmpty(mappingId) || mappingMap.containsKey(mappingId)) { + return; + } + + ResourceMapping mapping = new ResourceMapping(); + mapping.setId(mappingId); + mapping.setFilestoreId(rs.getString("plan_configuration_mapping_filestore_id")); + mapping.setMappedFrom(rs.getString("plan_configuration_mapping_mapped_from")); + mapping.setMappedTo(rs.getString("plan_configuration_mapping_mapped_to")); + mapping.setActive(rs.getBoolean("plan_configuration_mapping_active")); + + if (CollectionUtils.isEmpty(planConfigEntry.getResourceMapping())) { + List mappingList = new ArrayList<>(); + mappingList.add(mapping); + planConfigEntry.setResourceMapping(mappingList); + } else { + planConfigEntry.getResourceMapping().add(mapping); + } + + mappingMap.put(mappingId, mapping); + } + +} 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 new file mode 100644 index 00000000000..a82919fed46 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/repository/rowmapper/PlanRowMapper.java @@ -0,0 +1,247 @@ +package digit.repository.rowmapper; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +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; +import org.springframework.stereotype.Component; +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.*; + +@Component +public class PlanRowMapper implements ResultSetExtractor> { + + private ObjectMapper objectMapper; + + public PlanRowMapper(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + @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<>(); + + // Traverse through result set and create plan objects + while(rs.next()) { + String planId = rs.getString("plan_id"); + + Plan planEntry = planMap.get(planId); + + if(ObjectUtils.isEmpty(planEntry)) { + planEntry = new Plan(); + + // Prepare audit details + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(rs.getString("plan_created_by")) + .createdTime(rs.getLong("plan_created_time")) + .lastModifiedBy(rs.getString("plan_last_modified_by")) + .lastModifiedTime(rs.getLong("plan_last_modified_time")) + .build(); + + // 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.setPlanConfigurationId(rs.getString("plan_plan_configuration_id")); + planEntry.setAdditionalDetails(getAdditionalDetail((PGobject) rs.getObject("plan_additional_details"))); + planEntry.setAuditDetails(auditDetails); + + } + + addActivities(rs, planEntry, activityMap, conditionMap); + addResources(rs, planEntry, resourceMap); + addTargets(rs, planEntry, targetMap); + planMap.put(planId, planEntry); + } + + return new ArrayList<>(planMap.values()); + } + + private void addActivities(ResultSet rs, Plan plan, + Map activityMap, Map conditionMap) throws SQLException, DataAccessException { + + String activityId = rs.getString("plan_activity_id"); + + if(!ObjectUtils.isEmpty(activityId) && activityMap.containsKey(activityId)) { + addActivityConditions(rs, activityMap.get(activityId), conditionMap); + return; + } + else if (ObjectUtils.isEmpty(activityId)) { + // Set activities list to empty if no activity found + plan.setActivities(new ArrayList<>()); + return; + } + + String dependencies = rs.getString("plan_activity_dependencies"); + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(rs.getString("plan_activity_created_by")) + .createdTime(rs.getLong("plan_activity_created_time")) + .lastModifiedBy(rs.getString("plan_activity_last_modified_by")) + .lastModifiedTime(rs.getLong("plan_activity_last_modified_time")) + .build(); + + Activity activity = Activity.builder() + .id(activityId) + .code(rs.getString("plan_activity_code")) + .description(rs.getString("plan_activity_description")) + .plannedStartDate(rs.getLong("plan_activity_planned_start_date")) + .plannedEndDate(rs.getLong("plan_activity_planned_end_date")) + .dependencies(ObjectUtils.isEmpty(dependencies) ? new ArrayList<>() : Arrays.asList(rs.getString("plan_activity_dependencies").split(","))) + .build(); + + addActivityConditions(rs, activity, conditionMap); + + if (CollectionUtils.isEmpty(plan.getActivities())) { + List activityList = new ArrayList<>(); + activityList.add(activity); + plan.setActivities(activityList); + } else { + plan.getActivities().add(activity); + } + + activityMap.put(activity.getId(), activity); + + } + + private void addActivityConditions(ResultSet rs, Activity activity, Map conditionMap) throws SQLException, DataAccessException { + String conditionId = rs.getString("plan_activity_condition_id"); + + if(ObjectUtils.isEmpty(conditionId) || conditionMap.containsKey(conditionId)) { + List conditionList = new ArrayList<>(); + activity.setConditions(conditionList); + return; + } + + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(rs.getString("plan_activity_condition_created_by")) + .createdTime(rs.getLong("plan_activity_condition_created_time")) + .lastModifiedBy(rs.getString("plan_activity_condition_last_modified_by")) + .lastModifiedTime(rs.getLong("plan_activity_condition_last_modified_time")) + .build(); + + Condition condition = Condition.builder() + .id(conditionId) + .entity(rs.getString("plan_activity_condition_entity")) + .entityProperty(rs.getString("plan_activity_condition_entity_property")) + .expression(rs.getString("plan_activity_condition_expression")) + .build(); + + if(CollectionUtils.isEmpty(activity.getConditions())){ + List conditionList = new ArrayList<>(); + conditionList.add(condition); + activity.setConditions(conditionList); + } else { + activity.getConditions().add(condition); + } + + conditionMap.put(condition.getId(), condition); + + } + + private void addResources(ResultSet rs, Plan planEntry, Map resourceMap) throws SQLException, DataAccessException { + + String resourceId = rs.getString("plan_resource_id"); + + if(ObjectUtils.isEmpty(resourceId) || resourceMap.containsKey(resourceId)) { + List resourceList = new ArrayList<>(); + planEntry.setResources(resourceList); + return; + } + + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(rs.getString("plan_resource_created_by")) + .createdTime(rs.getLong("plan_resource_created_time")) + .lastModifiedBy(rs.getString("plan_resource_last_modified_by")) + .lastModifiedTime(rs.getLong("plan_resource_last_modified_time")) + .build(); + + Resource resource = Resource.builder() + .id(rs.getString("plan_resource_id")) + .resourceType(rs.getString("plan_resource_resource_type")) + .estimatedNumber(rs.getBigDecimal("plan_resource_estimated_number")) + .activityCode(rs.getString("plan_resource_activity_code")) + .build(); + + if (CollectionUtils.isEmpty(planEntry.getResources())) { + List resourceList = new ArrayList<>(); + resourceList.add(resource); + planEntry.setResources(resourceList); + } else { + planEntry.getResources().add(resource); + } + + resourceMap.put(resource.getId(), resource); + + } + + private void addTargets(ResultSet rs, Plan planEntry, Map targetMap) throws SQLException, DataAccessException { + String targetId = rs.getString("plan_target_id"); + + if(ObjectUtils.isEmpty(targetId) || targetMap.containsKey(targetId)) { + List targetList = new ArrayList<>(); + planEntry.setTargets(targetList); + return; + } + + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(rs.getString("plan_target_created_by")) + .createdTime(rs.getLong("plan_target_created_time")) + .lastModifiedBy(rs.getString("plan_target_last_modified_by")) + .lastModifiedTime(rs.getLong("plan_target_last_modified_time")) + .build(); + + MetricDetail metricDetail = MetricDetail.builder() + .metricValue(rs.getBigDecimal("plan_target_metric_value")) + .metricComparator(MetricDetail.MetricComparatorEnum.fromValue(rs.getString("plan_target_metric_comparator"))) + .metricUnit(rs.getString("plan_target_metric_unit")) + .build(); + + Target target = Target.builder() + .id(targetId) + .metric(rs.getString("plan_target_metric")) + .metricDetail(metricDetail) + .activityCode(rs.getString("plan_target_activity_code")) + .build(); + + if (CollectionUtils.isEmpty(planEntry.getTargets())) { + List targetList = new ArrayList<>(); + targetList.add(target); + planEntry.setTargets(targetList); + } else { + planEntry.getTargets().add(target); + } + + targetMap.put(target.getId(), target); + + } + + 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/service/PlanConfigurationService.java b/health-services/plan-service/src/main/java/digit/service/PlanConfigurationService.java new file mode 100644 index 00000000000..303d9477e70 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/PlanConfigurationService.java @@ -0,0 +1,88 @@ +package digit.service; + +import digit.config.Configuration; +import digit.kafka.Producer; +import digit.repository.impl.PlanConfigurationRepositoryImpl; +import digit.service.enrichment.EnrichmentService; +import digit.service.validator.PlanConfigurationValidator; +import digit.util.ResponseInfoFactory; +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; + +@Service +@Slf4j +public class PlanConfigurationService { + + private Producer producer; + + private EnrichmentService enrichmentService; + + private Configuration config; + + private PlanConfigurationValidator validator; + + private PlanConfigurationRepositoryImpl repository; + + private ResponseInfoFactory responseInfoFactory; + + public PlanConfigurationService(Producer producer, EnrichmentService enrichmentService, Configuration config + , PlanConfigurationValidator validator, PlanConfigurationRepositoryImpl repository, ResponseInfoFactory responseInfoFactory) { + this.producer = producer; + this.enrichmentService = enrichmentService; + this.config = config; + this.validator = validator; + this.repository = repository; + this.responseInfoFactory = responseInfoFactory; + } + + /** + * 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. + */ + public PlanConfigurationRequest create(PlanConfigurationRequest request) { + enrichmentService.enrichPlanConfigurationBeforeValidation(request); + validator.validateCreate(request); + enrichmentService.enrichCreate(request); + repository.create(request); + return request; + } + + /** + * 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(). + responseInfo(responseInfoFactory.createResponseInfoFromRequestInfo(request.getRequestInfo(), true)) + .planConfiguration(repository.search(request.getPlanConfigurationSearchCriteria())) + .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); + 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())) + .build(); + } +} \ No newline at end of file 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 new file mode 100644 index 00000000000..75d79c840a3 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/PlanEnricher.java @@ -0,0 +1,109 @@ +package digit.service; + +import digit.web.models.PlanRequest; +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; + +@Component +public class PlanEnricher { + + /** + * Enriches the plan create request + * @param body + */ + public void enrichPlanCreate(PlanRequest body) { + if (body.getPlan() == null) { + throw new IllegalArgumentException("Plan details are missing in the request."); + } + // Generate id for plan + UUIDEnrichmentUtil.enrichRandomUuid(body.getPlan(), "id"); + + // Generate id for activities + body.getPlan().getActivities().forEach(activity -> UUIDEnrichmentUtil.enrichRandomUuid(activity, "id")); + + // Generate id for activity conditions + body.getPlan().getActivities().forEach(activity -> { + if(!CollectionUtils.isEmpty(activity.getConditions())) { + UUIDEnrichmentUtil.enrichRandomUuid(activity.getConditions(), "id"); + } + }); + + // Set empty value in dependencies list when it is empty or null + body.getPlan().getActivities().forEach(activity -> { + if(CollectionUtils.isEmpty(activity.getDependencies())) { + List emptyStringList = new ArrayList<>(); + emptyStringList.add(""); + activity.setDependencies(emptyStringList); + } + }); + + // Generate id for resources + body.getPlan().getResources().forEach(resource -> UUIDEnrichmentUtil.enrichRandomUuid(resource, "id")); + + // Generate id for targets + body.getPlan().getTargets().forEach(target -> UUIDEnrichmentUtil.enrichRandomUuid(target, "id")); + + // Enrich audit details + body.getPlan().setAuditDetails(AuditDetailsEnrichmentUtil + .prepareAuditDetails(body.getPlan().getAuditDetails(), body.getRequestInfo(), Boolean.TRUE)); + + } + + /** + * Enriches the plan update request + * @param body + */ + public void enrichPlanUpdate(PlanRequest body) { + // Generate uuid for new activities + Set newActivityUuids = new HashSet<>(); + body.getPlan().getActivities().forEach(activity -> { + if(ObjectUtils.isEmpty(activity.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(activity, "id"); + newActivityUuids.add(activity.getId()); + } + }); + + // Generate uuid for new activity conditions + body.getPlan().getActivities().forEach(activity -> { + if(!CollectionUtils.isEmpty(activity.getConditions()) && newActivityUuids.contains(activity.getId())) { + activity.getConditions().forEach(condition -> { + if(ObjectUtils.isEmpty(condition.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(condition, "id"); + } + }); + } + }); + + // Set empty value in dependencies list when it is empty or null + body.getPlan().getActivities().forEach(activity -> { + if(CollectionUtils.isEmpty(activity.getDependencies())) { + List emptyStringList = new ArrayList<>(); + emptyStringList.add(""); + activity.setDependencies(emptyStringList); + } + }); + + // Generate uuid for new resources + body.getPlan().getResources().forEach(resource -> { + if(ObjectUtils.isEmpty(resource.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(resource, "id"); + } + }); + + // Generate uuid for new targets + body.getPlan().getTargets().forEach(target -> { + if(ObjectUtils.isEmpty(target.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(target, "id"); + } + }); + + } +} 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 new file mode 100644 index 00000000000..c0c97a30eaf --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/PlanService.java @@ -0,0 +1,89 @@ +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 org.egov.common.utils.ResponseInfoUtil; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Service +public class PlanService { + + private PlanValidator planValidator; + + private PlanEnricher planEnricher; + + private PlanRepository planRepository; + + public PlanService(PlanValidator planValidator, PlanEnricher planEnricher, PlanRepository planRepository) { + this.planValidator = planValidator; + this.planEnricher = planEnricher; + this.planRepository = planRepository; + } + + /** + * This method processes the requests that come for creating plans. + * @param body + * @return + */ + public PlanResponse createPlan(PlanRequest body) { + // Validate plan create request + planValidator.validatePlanCreate(body); + + // Enrich plan create request + planEnricher.enrichPlanCreate(body); + + // Delegate creation request to repository + planRepository.create(body); + + // Build and return response back to controller + return PlanResponse.builder() + .responseInfo(ResponseInfoUtil.createResponseInfoFromRequestInfo(body.getRequestInfo(), Boolean.TRUE)) + .plan(Collections.singletonList(body.getPlan())) + .build(); + } + + /** + * This method processes the requests that come for searching plans. + * @param body + * @return + */ + public PlanResponse searchPlan(PlanSearchRequest body) { + // Delegate search request to repository + List planList = planRepository.search(body.getPlanSearchCriteria()); + + // Build and return response back to controller + return PlanResponse.builder() + .responseInfo(ResponseInfoUtil.createResponseInfoFromRequestInfo(body.getRequestInfo(), Boolean.TRUE)) + .plan(planList) + .build(); + } + + /** + * This method processes the requests that come for updating plans. + * @param body + * @return + */ + public PlanResponse updatePlan(PlanRequest body) { + // Validate plan update request + planValidator.validatePlanUpdate(body); + + // Enrich plan update request + planEnricher.enrichPlanUpdate(body); + + // Delegate update request to repository + planRepository.update(body); + + // Build and return response back to controller + return PlanResponse.builder() + .responseInfo(ResponseInfoUtil.createResponseInfoFromRequestInfo(body.getRequestInfo(), Boolean.TRUE)) + .plan(Collections.singletonList(body.getPlan())) + .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 new file mode 100644 index 00000000000..b52c3450c6d --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/PlanValidator.java @@ -0,0 +1,383 @@ +package digit.service; + +import com.jayway.jsonpath.JsonPath; +import digit.repository.PlanConfigurationRepository; +import digit.repository.PlanRepository; +import digit.util.MdmsUtil; +import digit.web.models.*; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static digit.config.ServiceConstants.INVALID_PLAN_CONFIG_ID_CODE; +import static digit.config.ServiceConstants.INVALID_PLAN_CONFIG_ID_MESSAGE; +import static digit.config.ServiceConstants.JSONPATH_ERROR_CODE; +import static digit.config.ServiceConstants.JSONPATH_ERROR_MESSAGE; +import static digit.config.ServiceConstants.MDMS_MASTER_METRIC; +import static digit.config.ServiceConstants.MDMS_MASTER_UOM; +import static digit.config.ServiceConstants.MDMS_PLAN_MODULE_NAME; +import static digit.config.ServiceConstants.METRIC_NOT_FOUND_IN_MDMS_CODE; +import static digit.config.ServiceConstants.METRIC_NOT_FOUND_IN_MDMS_MESSAGE; +import static digit.config.ServiceConstants.METRIC_UNIT_NOT_FOUND_IN_MDMS_CODE; +import static digit.config.ServiceConstants.METRIC_UNIT_NOT_FOUND_IN_MDMS_MESSAGE; + +@Component +public class PlanValidator { + + private PlanRepository planRepository; + + private PlanConfigurationRepository planConfigurationRepository; + + private MdmsUtil mdmsUtil; + + public PlanValidator(PlanRepository planRepository, PlanConfigurationRepository planConfigurationRepository, MdmsUtil mdmsUtil) { + this.planRepository = planRepository; + this.planConfigurationRepository = planConfigurationRepository; + this.mdmsUtil = mdmsUtil; + } + + /** + * This method performs business validations on plan create requests + * @param request + */ + public void validatePlanCreate(PlanRequest request) { + String rootTenantId = request.getPlan().getTenantId().split("\\.")[0]; + Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), rootTenantId); + + // Validate activities + validateActivities(request); + + // Validate plan configuration existence + validatePlanConfigurationExistence(request); + + // Validate resources + validateResources(request); + + // Validate resource-activity linkage + validateResourceActivityLinkage(request); + + // Validate target-activity linkage + validateTargetActivityLinkage(request); + + // Validate dependencies + validateActivityDependencies(request); + + // Validate Target's Metrics against MDMS + validateTargetMetrics(request, mdmsData); + + // Validate Metric Detail's Unit against MDMS + validateMetricDetailUnit(request, mdmsData); + } + + /** + * This validation method validates if the dependent activities are valid and if they form a cycle + * @param request + */ + private void validateActivityDependencies(PlanRequest request) { + // Check if dependent activity codes are valid + validateDependentActivityCodes(request); + + // Check if dependent activities form a cycle + checkForCycleInActivityDependencies(request); + } + + /** + * This method checks if the activity dependencies form a cycle + * @param request + */ + private void checkForCycleInActivityDependencies(PlanRequest request) { + Map> activityCodeVsDependenciesMap = request.getPlan().getActivities().stream() + .collect(Collectors.toMap(Activity::getCode, + activity -> CollectionUtils.isEmpty(activity.getDependencies()) ? List.of() : activity.getDependencies())); + + activityCodeVsDependenciesMap.keySet().forEach(activityCode -> { + activityCodeVsDependenciesMap.get(activityCode).forEach(dependency -> { + if(activityCodeVsDependenciesMap.get(dependency).contains(activityCode)) + throw new CustomException("CYCLIC_ACTIVITY_DEPENDENCY", "Cyclic activity dependency found"); + }); + }); + } + + /** + * This method validates if the dependent activity codes are valid + * @param request + */ + private void validateDependentActivityCodes(PlanRequest request) { + // Collect all activity codes + Set activityCodes = request.getPlan().getActivities().stream() + .map(Activity::getCode) + .collect(Collectors.toSet()); + + // Check if the dependent activity codes are valid + request.getPlan().getActivities().forEach(activity -> { + if(!CollectionUtils.isEmpty(activity.getDependencies())) { + activity.getDependencies().forEach(dependency -> { + if(!activityCodes.contains(dependency)) + throw new CustomException("INVALID_ACTIVITY_DEPENDENCY", "Activity dependency is invalid"); + }); + } + }); + } + + + /** + * 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) + throw new CustomException("ACTIVITIES_CANNOT_BE_NULL","Activities list in Plan cannot be null"); + + Set activityCodes = request.getPlan().getActivities().stream() + .map(Activity::getCode) + .collect(Collectors.toSet()); + + // If activity codes are not unique, throw an exception + if(activityCodes.size() != request.getPlan().getActivities().size()) { + throw new CustomException("DUPLICATE_ACTIVITY_CODES", "Activity codes within the plan should be unique"); + } + + // If execution plan id is not provided, providing activities is mandatory + if(ObjectUtils.isEmpty(request.getPlan().getExecutionPlanId()) + && CollectionUtils.isEmpty(request.getPlan().getActivities())) { + throw new CustomException("PLAN_ACTIVITIES_MANDATORY", "Activities are mandatory if execution plan id is not provided"); + } + + // If execution plan id is provided, providing activities is not allowed + if(!ObjectUtils.isEmpty(request.getPlan().getExecutionPlanId()) + && !CollectionUtils.isEmpty(request.getPlan().getActivities())) { + throw new CustomException("PLAN_ACTIVITIES_NOT_ALLOWED", "Activities are not allowed if execution plan id is provided"); + } + + // Validate activity dates + if(!CollectionUtils.isEmpty(request.getPlan().getActivities())) { + request.getPlan().getActivities().forEach(activity -> { + if(activity.getPlannedEndDate() < activity.getPlannedStartDate()) + throw new CustomException("INVALID_ACTIVITY_DATES", "Planned end date cannot be before planned start date"); + }); + } + } + + /** + * 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()))) { + 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()) + && CollectionUtils.isEmpty(request.getPlan().getResources())) { + throw new CustomException("PLAN_RESOURCES_MANDATORY", "Resources are mandatory if plan configuration id is not provided"); + } + + // 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", "Resources are not allowed if plan configuration id is provided"); + } + + // 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()) + && !CollectionUtils.isEmpty(request.getPlan().getActivities())) { + // Collect all activity codes + Set activityCodes = request.getPlan().getActivities().stream() + .map(Activity::getCode) + .collect(Collectors.toSet()); + + // Validate resource-activity linkage + request.getPlan().getResources().forEach(resource -> { + if(!activityCodes.contains(resource.getActivityCode())) + throw new CustomException("INVALID_RESOURCE_ACTIVITY_LINKAGE", "Resource-Activity linkage is invalid"); + }); + } + } + + /** + * This method validates the linkage between targets and activities + * @param request + */ + private void validateTargetActivityLinkage(PlanRequest request) { + if(!CollectionUtils.isEmpty(request.getPlan().getActivities())) { + // Collect all activity codes + Set activityCodes = request.getPlan().getActivities().stream() + .map(Activity::getCode) + .collect(Collectors.toSet()); + + // Validate target-activity linkage + request.getPlan().getTargets().forEach(target -> { + if(!activityCodes.contains(target.getActivityCode())) + throw new CustomException("INVALID_TARGET_ACTIVITY_LINKAGE", "Target-Activity linkage is invalid"); + }); + } + } + + /** + * This method performs business validations on plan update requests + * @param request + */ + public void validatePlanUpdate(PlanRequest request) { + // Validate plan existence + validatePlanExistence(request); + + String rootTenantId = request.getPlan().getTenantId().split("\\.")[0]; + Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), rootTenantId); + + // Validate activities + validateActivities(request); + + // Validate activities uuid uniqueness + validateActivitiesUuidUniqueness(request); + + // Validate plan configuration existence + validatePlanConfigurationExistence(request); + + // Validate resources + validateResources(request); + + // Validate resource uuid uniqueness + validateResourceUuidUniqueness(request); + + // Validate target uuid uniqueness + validateTargetUuidUniqueness(request); + + // Validate resource-activity linkage + validateResourceActivityLinkage(request); + + // Validate target-activity linkage + validateTargetActivityLinkage(request); + + // Validate dependencies + validateActivityDependencies(request); + + // Validate Target's Metrics against MDMS + validateTargetMetrics(request, mdmsData); + + // Validate Metric Detail's Unit against MDMS + validateMetricDetailUnit(request, mdmsData); + + } + + private void validateTargetUuidUniqueness(PlanRequest request) { + // Collect all target uuids + Set targetUuids = request.getPlan().getTargets().stream() + .map(Target::getId) + .collect(Collectors.toSet()); + + // If target uuids are not unique, throw an exception + if(targetUuids.size() != request.getPlan().getTargets().size()) { + throw new CustomException("DUPLICATE_TARGET_UUIDS", "Target uuids should be unique"); + } + } + + private void validateResourceUuidUniqueness(PlanRequest request) { + // Collect all resource uuids + Set resourceUuids = request.getPlan().getResources().stream() + .map(Resource::getId) + .collect(Collectors.toSet()); + + // If resource uuids are not unique, throw an exception + if(resourceUuids.size() != request.getPlan().getResources().size()) { + throw new CustomException("DUPLICATE_RESOURCE_UUIDS", "Resource uuids should be unique"); + } + } + + private void validateActivitiesUuidUniqueness(PlanRequest request) { + // Collect all activity uuids + Set activityUuids = request.getPlan().getActivities().stream() + .map(Activity::getId) + .collect(Collectors.toSet()); + + // If activity uuids are not unique, throw an exception + if(activityUuids.size() != request.getPlan().getActivities().size()) { + throw new CustomException("DUPLICATE_ACTIVITY_UUIDS", "Activity uuids should be unique"); + } + } + + /** + * This method validates if the plan id provided in the update request exists + * @param request + */ + private void validatePlanExistence(PlanRequest request) { + // If plan id provided is invalid, throw an exception + if(CollectionUtils.isEmpty(planRepository.search(PlanSearchCriteria.builder() + .ids(Collections.singleton(request.getPlan().getId())) + .build()))) { + throw new CustomException("INVALID_PLAN_ID", "Plan id provided is invalid"); + } + } + + public void validateTargetMetrics(PlanRequest request, Object mdmsData) { + Plan plan = request.getPlan(); + final String jsonPathForMetric = "$." + MDMS_PLAN_MODULE_NAME + "." + MDMS_MASTER_METRIC + ".*.code"; + + List metricListFromMDMS = null; + System.out.println("Jsonpath -> " + jsonPathForMetric); + try { + metricListFromMDMS = JsonPath.read(mdmsData, jsonPathForMetric); + } catch (Exception e) { + throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); + } + + for (Target target : plan.getTargets()) { + if (!metricListFromMDMS.contains(target.getMetric())) { + throw new CustomException(METRIC_NOT_FOUND_IN_MDMS_CODE, METRIC_NOT_FOUND_IN_MDMS_MESSAGE); + } + } + } + + public void validateMetricDetailUnit(PlanRequest request, Object mdmsData) { + Plan plan = request.getPlan(); + + List metricDetails = plan.getTargets().stream() + .map(Target::getMetricDetail) + .toList(); + + List metricUnitListFromMDMS = null; + final String jsonPathForMetricUnit = "$." + MDMS_PLAN_MODULE_NAME + "." + MDMS_MASTER_UOM + ".*.code"; + try { + metricUnitListFromMDMS = JsonPath.read(mdmsData, jsonPathForMetricUnit); + } catch (Exception e) { + throw new CustomException(JSONPATH_ERROR_CODE, JSONPATH_ERROR_MESSAGE); + } + + for (MetricDetail metricDetail : metricDetails) { + if (!metricUnitListFromMDMS.contains(metricDetail.getMetricUnit())) { + throw new CustomException(METRIC_UNIT_NOT_FOUND_IN_MDMS_CODE, METRIC_UNIT_NOT_FOUND_IN_MDMS_MESSAGE); + } + } + } + +} 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 new file mode 100644 index 00000000000..787e5ce2766 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/enrichment/EnrichmentService.java @@ -0,0 +1,186 @@ +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 lombok.extern.slf4j.Slf4j; +import org.egov.common.utils.AuditDetailsEnrichmentUtil; +import org.egov.common.utils.UUIDEnrichmentUtil; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; + +import java.util.List; +import static digit.config.ServiceConstants.USERINFO_MISSING_CODE; +import static digit.config.ServiceConstants.USERINFO_MISSING_MESSAGE; +import org.springframework.util.ObjectUtils; + +@Component +@Slf4j +public class EnrichmentService { + private Configuration config; + + public EnrichmentService(Configuration config) { + this.config = config; + } + + /** + * Enriches the PlanConfigurationRequest for creating a new plan configuration. + * This method enriches the plan configuration with generated IDs, 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. + */ + public void enrichCreate(PlanConfigurationRequest request) { + enrichPlanConfiguration(request.getPlanConfiguration()); + if(ObjectUtils.isEmpty(request.getRequestInfo().getUserInfo())) + throw new CustomException(USERINFO_MISSING_CODE, USERINFO_MISSING_MESSAGE); + + enrichAuditDetails(request, Boolean.TRUE); + } + + /** + * Enriches the given plan configuration with generated IDs for plan, files, assumptions, operations, and resource mappings. + * @param planConfiguration The PlanConfiguration to be enriched. + */ + public void enrichPlanConfiguration(PlanConfiguration planConfiguration) { + log.info("Enriching plan config with generated IDs"); + + // 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()); + }); + + + // Generate id for assumptions + planConfiguration.getAssumptions().forEach(assumption -> UUIDEnrichmentUtil.enrichRandomUuid(assumption, "id")); + + // Generate id for operations + planConfiguration.getOperations().forEach(operation -> UUIDEnrichmentUtil.enrichRandomUuid(operation, "id")); + + // Generate id for resource mappings + planConfiguration.getResourceMapping().forEach(resourceMapping -> UUIDEnrichmentUtil.enrichRandomUuid(resourceMapping, "id")); + } + + /** + * Enriches the audit details for the PlanConfigurationRequest based on the operation type (create or update). + * @param request The PlanConfigurationRequest for which audit details are to be enriched. + * @param isCreate A boolean indicating whether the operation is a create or update operation. + */ + public void enrichAuditDetails(PlanConfigurationRequest request, Boolean isCreate) { + PlanConfiguration planConfiguration = request.getPlanConfiguration(); + planConfiguration.setAuditDetails(AuditDetailsEnrichmentUtil + .prepareAuditDetails(planConfiguration.getAuditDetails(), request.getRequestInfo(), isCreate)); + } + + /** + * 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. + */ + public void enrichUpdate(PlanConfigurationRequest request) { + enrichPlanConfigurationForUpdate(request); + if (request.getRequestInfo().getUserInfo() == null) + throw new CustomException(USERINFO_MISSING_CODE, USERINFO_MISSING_MESSAGE); + + enrichAuditDetails(request, Boolean.FALSE); + } + + /** + * Enriches the plan configuration for update by generating IDs for files, assumptions, operations, and resource mappings if they are empty. + * @param request The PlanConfigurationRequest to be enriched for update operation. + */ + public void enrichPlanConfigurationForUpdate(PlanConfigurationRequest request) { + PlanConfiguration planConfiguration = request.getPlanConfiguration(); + + // For Files + planConfiguration.getFiles().forEach(file -> { + if (ObjectUtils.isEmpty(file.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(file, "id"); + } + enrichActiveForResourceMapping(file, request.getPlanConfiguration().getResourceMapping()); + }); + + // For Assumptions + planConfiguration.getAssumptions().forEach(assumption -> { + if (ObjectUtils.isEmpty(assumption.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(assumption, "id"); + } + }); + + // For Operations + planConfiguration.getOperations().forEach(operation -> { + if (ObjectUtils.isEmpty(operation.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(operation, "id"); + } + }); + + // For ResourceMappings + planConfiguration.getResourceMapping().forEach(resourceMapping -> { + if (ObjectUtils.isEmpty(resourceMapping.getId())) { + UUIDEnrichmentUtil.enrichRandomUuid(resourceMapping, "id"); + } + }); + + } + + /** + * Sets all corresponding resource mappings to inactive if the given file is 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) { + if (!file.getActive()) { + // Set all corresponding resource mappings to inactive + for (ResourceMapping mapping : resourceMappings) { + if (mapping.getFilestoreId().equals(file.getFilestoreId())) { + mapping.setActive(false); + } + } + } + } + + /** + * Enriches the plan configuration within the request before validation. + * For Files, Operations, Assumptions, and Resource Mappings without an ID, + * overrides the active status to be true. + * + * @param request the plan configuration request containing the plan configuration to be enriched + */ + 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); + } + }); + } + +} 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 new file mode 100644 index 00000000000..115c19855d8 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/service/validator/PlanConfigurationValidator.java @@ -0,0 +1,424 @@ +package digit.service.validator; + +import com.jayway.jsonpath.JsonPath; +import digit.config.ServiceConstants; +import digit.repository.PlanConfigurationRepository; +import digit.util.MdmsUtil; +import digit.web.models.*; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import static digit.config.ServiceConstants.*; + +@Component +@Slf4j +public class PlanConfigurationValidator { + + + private MdmsUtil mdmsUtil; + + private PlanConfigurationRepository planConfigRepository; + + public PlanConfigurationValidator(MdmsUtil mdmsUtil, PlanConfigurationRepository planConfigRepository) { + this.mdmsUtil = mdmsUtil; + this.planConfigRepository = planConfigRepository; + } + + /** + * 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 = planConfiguration.getTenantId().split("\\.")[0]; + Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), rootTenantId); + + validateAssumptionKeyAgainstMDMS(request, mdmsData); + validateAssumptionValue(planConfiguration); + validateFilestoreId(planConfiguration); + validateTemplateIdentifierAgainstMDMS(request, mdmsData); + validateOperationsInputAgainstMDMS(request, mdmsData); + validateResourceMappingAgainstMDMS(request, mdmsData); + validateMappedToUniqueness(planConfiguration.getResourceMapping()); + } + + /** + * Validates the assumption values against the assumption keys in the plan configuration. + * If an operation uses an inactive assumption, throws an exception. + * + * @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()); + + List operations = planConfiguration.getOperations(); + for (Operation operation : operations) { + // Check if the operation is using an assumption key that is not in the set of active assumption keys + if (operation.getActive() && !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 mdmsData The MDMS data. + */ + public void validateAssumptionKeyAgainstMDMS(PlanConfigurationRequest request, Object mdmsData) { + PlanConfiguration planConfiguration = request.getPlanConfiguration(); + final String jsonPathForAssumption = "$." + MDMS_PLAN_MODULE_NAME + "." + MDMS_MASTER_ASSUMPTION + "[*].assumptions[*]"; + + 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); + } + + for(Assumption assumption : planConfiguration.getAssumptions()) + { + if(!assumptionListFromMDMS.contains(assumption.getKey())) + { + log.error("Assumption Key " + assumption.getKey() + " is not present in MDMS"); + throw new CustomException(ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_CODE, ASSUMPTION_KEY_NOT_FOUND_IN_MDMS_MESSAGE + " at JSONPath: " + jsonPathForAssumption); + } + } + } + + /** + * Validates the file store IDs in the provided PlanConfiguration's Resource Mapping list. + * @param planConfiguration The PlanConfiguration to validate. + */ + public void validateFilestoreId(PlanConfiguration planConfiguration) { + Set fileStoreIds = planConfiguration.getFiles().stream() + .map(File::getFilestoreId) + .collect(Collectors.toSet()); + + List resourceMappingList = planConfiguration.getResourceMapping(); + for (ResourceMapping mapping : resourceMappingList) { + 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); + } + } + } + + /** + * 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. + */ + public void validateTemplateIdentifierAgainstMDMS(PlanConfigurationRequest request, Object mdmsData) { + PlanConfiguration planConfiguration = request.getPlanConfiguration(); + final String jsonPathForTemplateIdentifier = "$." + MDMS_PLAN_MODULE_NAME + "." + MDMS_MASTER_UPLOAD_CONFIGURATION + ".*.id"; + final String jsonPathForTemplateIdentifierIsRequired = "$." + MDMS_PLAN_MODULE_NAME + "." + 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); + } + + for(File file : planConfiguration.getFiles()) + { + if(!templateIdentifierListFromMDMS.contains(file.getTemplateIdentifier())) + { + log.error("Template Identifier " + file.getTemplateIdentifier() + " is not present in MDMS"); + 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 (requiredTemplateIdentifierFromMDMS.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 with the required Template Identifier should be present " + 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 + for (Object requiredTemplate : requiredTemplateIdentifierFromMDMS) { + 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 = "$." + MDMS_PLAN_MODULE_NAME + "." + 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); + } + List allowedColumns = getRuleConfigInputsFromSchema(ruleInputsListFromMDMS, templateIds, inputFileTypes); + planConfiguration.getOperations().stream() + .map(Operation::getOutput) + .forEach(allowedColumns::add); + for (Operation operation : planConfiguration.getOperations()) { + 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); + } + } + } + + // helper function + public static List getRuleConfigInputsFromSchema(List schemas, List templateIds, List inputFileTypes) { + if (schemas == null) { + return new ArrayList<>(); + } + Set 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 ArrayList<>(); + for(Map.Entry column : columns.entrySet()){ + LinkedHashMap data = column.getValue(); + if(data.get(MDMS_SCHEMA_PROPERTIES_IS_RULE_CONFIGURE_INPUT)){ + finalData.add(column.getKey()); + } + } + } + return new ArrayList<>(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<>(); + for (ResourceMapping mapping : resourceMappings) { + 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) { + validateSearchCriteria(planConfigurationSearchRequest); + } + + private void validateSearchCriteria(PlanConfigurationSearchRequest planConfigurationSearchRequest) { + if (Objects.isNull(planConfigurationSearchRequest.getPlanConfigurationSearchCriteria())) { + throw new CustomException(SEARCH_CRITERIA_EMPTY_CODE, SEARCH_CRITERIA_EMPTY_MESSAGE); + } + + if (StringUtils.isEmpty(planConfigurationSearchRequest.getPlanConfigurationSearchCriteria().getTenantId())) { + throw new CustomException(TENANT_ID_EMPTY_CODE, TENANT_ID_EMPTY_MESSAGE); + } + } + + + /** + * 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 = planConfiguration.getTenantId().split("\\.")[0]; + Object mdmsData = mdmsUtil.fetchMdmsData(request.getRequestInfo(), rootTenantId); + + // Validate plan existence + PlanConfiguration planConfigurationFromDB = validatePlanConfigExistence(request); + + validateAssumptionKeyAgainstMDMS(request, mdmsData); + validateAssumptionValue(planConfiguration); + validateFilestoreId(planConfiguration); +// validateFilesActive(planConfigurationFromDB, planConfiguration); + validateTemplateIdentifierAgainstMDMS(request, mdmsData); + validateOperationsInputAgainstMDMS(request, mdmsData); + validateOperationDependencies(planConfiguration); + validateResourceMappingAgainstMDMS(request, mdmsData); + validateMappedToUniqueness(planConfiguration.getResourceMapping()); + + } + + /** + * 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) { + // If plan id provided is invalid, throw an exception + List planConfigurationList = planConfigRepository.search(PlanConfigurationSearchCriteria.builder() + .id(request.getPlanConfiguration().getId()) + .build()); + + if(CollectionUtils.isEmpty(planConfigurationList)) { + throw new CustomException(INVALID_PLAN_CONFIG_ID_CODE, INVALID_PLAN_CONFIG_ID_MESSAGE); + } + + return planConfigurationList.get(0); + } + + /** + * Validates that if an operation is inactive, its output is not used as input in any other active operation. + * If the condition is violated, it logs an error and throws a CustomException. + * + * @param planConfiguration The plan configuration to validate. + * @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()); + + // Check for each inactive operation + for (Operation operation : planConfiguration.getOperations()) { + 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()); + } + } + } + + + /** + * 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) + .collect(Collectors.toList()); + List inputFileTypes = files.stream() + .map(File::getInputFileType) + .map(File.InputFileTypeEnum::toString) + .collect(Collectors.toList()); + + final String jsonPathForRuleInputs = "$." + MDMS_PLAN_MODULE_NAME + "." + 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); + } + List requiredColumns = getIsTruePropertyFromSchema(ruleInputsListFromMDMS, 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)); + + if (!exists) { + throw new CustomException(BOUNDARY_CODE_MAPPING_NOT_FOUND_CODE, BOUNDARY_CODE_MAPPING_NOT_FOUND_MESSAGE); + } + } + } + + + /** + * Return all properties that has isTrue flag as a true. + * @param schemas schema object. + * @param templateIds template ids list. + * @param inputFileTypes list of file type. + * @return + */ + public static List getIsTruePropertyFromSchema(List schemas, List templateIds, List inputFileTypes) { + if (schemas == null) { + return new ArrayList<>(); + } + Set 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 ArrayList<>(); + for(Map.Entry column : columns.entrySet()){ + LinkedHashMap data = column.getValue(); + if(data.get(MDMS_SCHEMA_PROPERTIES_IS_REQUIRED)){ + finalData.add(column.getKey()); + } + } + } + return new ArrayList<>(finalData); + } + + public void validateFilesActive(PlanConfiguration planConfigurationFromDB, PlanConfiguration planConfiguration) + { + // Create a map of files from planConfigurationFromDB using the file ID as the key + Map filesFromDBMap = planConfigurationFromDB.getFiles().stream() + .collect(Collectors.toMap(File::getId, file -> file)); + + // Iterate over the files in planConfiguration + for (File file : planConfiguration.getFiles()) { + File dbFile = filesFromDBMap.get(file.getId()); + // If the file exists in planConfigurationFromDB and has been made active after being inactive + if (dbFile == null) { + throw new CustomException("FILES_ACTIVE_STATUS_CHANGE_NOT_ALLOWED", "Files cannot be made active after being inactive, please upload new file"); + } + } + } +} 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 new file mode 100644 index 00000000000..4e301a3e5f5 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/util/MdmsUtil.java @@ -0,0 +1,90 @@ +package digit.util; + +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.*; + +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; +import org.springframework.web.client.RestTemplate; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static digit.config.ServiceConstants.*; + +@Slf4j +@Component +public class MdmsUtil { + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private ObjectMapper mapper; + + @Autowired + private Configuration configs; + + + 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<>(); + MdmsResponse mdmsResponse = new MdmsResponse(); + try { + 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); + } + + Object result = mdmsResponse.getMdmsRes(); + if (result == null || ObjectUtils.isEmpty(result)) { + log.error(NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE + " - " + tenantId); + throw new CustomException(NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_CODE, NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE); + } + return result; + } + + public MdmsCriteriaReq getMdmsRequest(RequestInfo requestInfo, String tenantId) { + + ModuleDetail assumptionModuleDetail = getPlanModuleDetail(); + + List moduleDetails = new LinkedList<>(); + moduleDetails.add(assumptionModuleDetail); + + MdmsCriteria mdmsCriteria = MdmsCriteria.builder().moduleDetails(moduleDetails).tenantId(tenantId).build(); + + return MdmsCriteriaReq.builder().mdmsCriteria(mdmsCriteria).requestInfo(requestInfo).build(); + } + + private ModuleDetail getPlanModuleDetail() { + List assumptionMasterDetails = new ArrayList<>(); + + MasterDetail assumptionMasterDetail = MasterDetail.builder().name(MDMS_MASTER_ASSUMPTION).build(); + MasterDetail uploadConfigMasterDetail = MasterDetail.builder().name(MDMS_MASTER_UPLOAD_CONFIGURATION).build(); + MasterDetail ruleConfigureInputsMasterDetail = MasterDetail.builder().name(MDMS_MASTER_RULE_CONFIGURE_INPUTS).filter(FILTER_DATA).build(); + MasterDetail schemaDetails = MasterDetail.builder().name(MDMS_MASTER_SCHEMAS).build(); + MasterDetail metricDetails = MasterDetail.builder().name(MDMS_MASTER_METRIC).build(); + MasterDetail UnitDetails = MasterDetail.builder().name(MDMS_MASTER_UOM).build(); + + assumptionMasterDetails.add(assumptionMasterDetail); + assumptionMasterDetails.add(uploadConfigMasterDetail); + assumptionMasterDetails.add(ruleConfigureInputsMasterDetail); + assumptionMasterDetails.add(schemaDetails); + assumptionMasterDetails.add(metricDetails); + assumptionMasterDetails.add(UnitDetails); + + return ModuleDetail.builder().masterDetails(assumptionMasterDetails).moduleName(MDMS_PLAN_MODULE_NAME).build(); + } + +} \ No newline at end of file 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 new file mode 100644 index 00000000000..84817b60870 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/util/QueryUtil.java @@ -0,0 +1,126 @@ +package digit.util; + +import com.google.gson.Gson; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.IntStream; + +import static digit.config.ServiceConstants.DOT_REGEX; +import static digit.config.ServiceConstants.DOT_SEPARATOR; + + +public class QueryUtil { + + private QueryUtil(){} + + private static final Gson gson = new Gson(); + + /** + * 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()){ + 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 + * @return + */ + public static 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 + * @param ids + */ + public static void addToPreparedStatement(List preparedStmtList, Set 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){ + 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) { + Map queryMap = new HashMap<>(); + + filterMap.keySet().forEach(key -> { + 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{ + queryMap.put(key, filterMap.get(key)); + } + }); + + String partialJsonQueryString = gson.toJson(queryMap); + + return partialJsonQueryString; + } + + /** + * 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) { + // Return when all levels have been reached. + if(index == nestedKeyArray.length) + return; + + // For the final level simply put the value in the map. + else if (index == nestedKeyArray.length - 1) { + currentQueryMap.put(nestedKeyArray[index], value); + return; + } + + // For non terminal levels, add a child map. + currentQueryMap.put(nestedKeyArray[index], new HashMap<>()); + + // Make a recursive call to enrich data in next level. + prepareNestedQueryMap(index + 1, nestedKeyArray, (Map) currentQueryMap.get(nestedKeyArray[index]), value); + } + +} diff --git a/health-services/plan-service/src/main/java/digit/util/ResponseInfoFactory.java b/health-services/plan-service/src/main/java/digit/util/ResponseInfoFactory.java new file mode 100644 index 00000000000..a10e7f50841 --- /dev/null +++ b/health-services/plan-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/plan-service/src/main/java/digit/web/controllers/PlanConfigController.java b/health-services/plan-service/src/main/java/digit/web/controllers/PlanConfigController.java new file mode 100644 index 00000000000..1577ce3dbb1 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/controllers/PlanConfigController.java @@ -0,0 +1,80 @@ +package digit.web.controllers; + + +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; +import jakarta.validation.Valid; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestMapping; +import java.util.*; + +@Controller +public class PlanConfigController { + + private ObjectMapper objectMapper; + + private PlanConfigurationService planConfigurationService; + + private ResponseInfoFactory responseInfoFactory; + + @Autowired + public PlanConfigController(ObjectMapper objectMapper, PlanConfigurationService planConfigurationService, ResponseInfoFactory responseInfoFactory) { + this.objectMapper = objectMapper; + this.planConfigurationService = planConfigurationService; + this.responseInfoFactory = responseInfoFactory; + } + + /** + * Request handler for serving plan configuration create requests + * @param body + * @return + */ + @RequestMapping(value = "/config/_create", method = RequestMethod.POST) + public ResponseEntity configCreatePost(@Parameter(in = ParameterIn.DEFAULT, description = "", schema = @Schema()) @Valid @RequestBody PlanConfigurationRequest body) { + + PlanConfigurationRequest planConfigurationRequest = planConfigurationService.create(body); + PlanConfigurationResponse response = PlanConfigurationResponse.builder() + .planConfiguration(Collections.singletonList(planConfigurationRequest.getPlanConfiguration())) + .responseInfo(responseInfoFactory + .createResponseInfoFromRequestInfo(body.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + + } + + /** + * Request handler for serving plan configuration search requests + * @param body + * @return + */ + @RequestMapping(value = "/config/_search", method = RequestMethod.POST) + public ResponseEntity configSearchPost(@Parameter(in = ParameterIn.DEFAULT, description = "", schema = @Schema()) @Valid @RequestBody PlanConfigurationSearchRequest body) { + PlanConfigurationResponse response = planConfigurationService.search(body); + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + /** + * Request handler for serving plan configuration update requests + * @param body + * @return + */ + @RequestMapping(value = "/config/_update", method = RequestMethod.POST) + public ResponseEntity configUpdatePost(@Parameter(in = ParameterIn.DEFAULT, description = "", schema = @Schema()) @Valid @RequestBody PlanConfigurationRequest body) { + PlanConfigurationResponse response = planConfigurationService.update(body); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } +} 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 new file mode 100644 index 00000000000..2381b009d40 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/controllers/PlanController.java @@ -0,0 +1,60 @@ +package digit.web.controllers; + + +import digit.service.PlanService; +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.RequestMethod; +import org.springframework.web.bind.annotation.RequestMapping; + + +@Validated +@Controller +@RequestMapping("/plan") +public class PlanController { + + private PlanService planService; + + public PlanController(PlanService planService) { + this.planService = planService; + } + + /** + * Request handler for serving plan create requests + * @param body + * @return + */ + @RequestMapping(value = "/_create", method = RequestMethod.POST) + public ResponseEntity createPost(@Valid @RequestBody PlanRequest body) { + PlanResponse planResponse = planService.createPlan(body); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(planResponse); + } + + /** + * Request handler for serving plan search requests + * @param body + * @return + */ + @RequestMapping(value = "/_search", method = RequestMethod.POST) + public ResponseEntity searchPost(@Valid @RequestBody PlanSearchRequest body) { + PlanResponse planResponse = planService.searchPlan(body); + return ResponseEntity.status(HttpStatus.OK).body(planResponse); + } + + /** + * Request handler for serving plan update requests + * @param body + * @return + */ + @RequestMapping(value = "/_update", method = RequestMethod.POST) + public ResponseEntity updatePost(@Valid @RequestBody PlanRequest body) { + PlanResponse planResponse = planService.updatePlan(body); + return ResponseEntity.status(HttpStatus.ACCEPTED).body(planResponse); + } + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/Activity.java b/health-services/plan-service/src/main/java/digit/web/models/Activity.java new file mode 100644 index 00000000000..15f15209259 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/Activity.java @@ -0,0 +1,51 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +import jakarta.validation.constraints.Size; +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; + +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * Activity + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Activity { + @JsonProperty("id") + private String id = null; + + @JsonProperty("code") + @NotNull + @Size(min = 2, max = 128) + private String code = null; + + @JsonProperty("description") + @Size(max = 2048) + private String description = null; + + @JsonProperty("plannedStartDate") + private Long plannedStartDate = null; + + @JsonProperty("plannedEndDate") + private Long plannedEndDate = null; + + @JsonProperty("dependencies") + private List dependencies = null; + + @JsonProperty("conditions") + @Valid + private List conditions = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/Assumption.java b/health-services/plan-service/src/main/java/digit/web/models/Assumption.java new file mode 100644 index 00000000000..a4b7e3ad01f --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/Assumption.java @@ -0,0 +1,49 @@ +package digit.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("active") + @NotNull + private Boolean active = true; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/Condition.java b/health-services/plan-service/src/main/java/digit/web/models/Condition.java new file mode 100644 index 00000000000..a30525b2f45 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/Condition.java @@ -0,0 +1,40 @@ +package digit.web.models; + +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.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * Condition + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Condition { + + @JsonProperty + private String id = null; + + @JsonProperty("entity") + @NotNull + @Size(min = 2, max = 64) + private String entity = null; + + @JsonProperty("entityProperty") + @NotNull + @Size(min = 2, max = 64) + private String entityProperty = null; + + @JsonProperty("expression") + @NotNull + @Size(min = 3, max = 2048) + private String expression = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/File.java b/health-services/plan-service/src/main/java/digit/web/models/File.java new file mode 100644 index 00000000000..68cf28cd46b --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/File.java @@ -0,0 +1,84 @@ +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.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.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * File + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class File { + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("filestoreId") + @NotNull + @Size(min = 1, max = 128) + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Filestore Id must not contain only special characters") + private String filestoreId = null; + + @JsonProperty("inputFileType") + @NotNull + private InputFileTypeEnum inputFileType = null; + + @JsonProperty("templateIdentifier") + @NotNull + @Size(min = 2, max = 128) + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Name must not contain only special characters") + private String templateIdentifier = null; + + @JsonProperty("active") + @NotNull + private Boolean active = true; + + /** + * The original file type of the Input + */ + public enum InputFileTypeEnum { + EXCEL("Excel"), + + SHAPEFILE("Shapefile"), + + GEOJSON("GeoJSON"); + + private String value; + + InputFileTypeEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static InputFileTypeEnum fromValue(String text) { + for (InputFileTypeEnum b : InputFileTypeEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/MetricDetail.java b/health-services/plan-service/src/main/java/digit/web/models/MetricDetail.java new file mode 100644 index 00000000000..40452bb02d1 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/MetricDetail.java @@ -0,0 +1,76 @@ +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.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; + +@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) { + for (MetricComparatorEnum b : MetricComparatorEnum.values()) { + if (String.valueOf(b.symbol).equals(text)) { + return b; + } + } + return null; + } + } + +} 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 new file mode 100644 index 00000000000..0569dc9a536 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/Operation.java @@ -0,0 +1,92 @@ +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.NotNull; +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; + +/** + * Operation + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Operation { + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("input") + @NotNull + @Size(min = 1, max = 256) + private String input = null; + + @JsonProperty("operator") + @NotNull + private OperatorEnum operator = null; + + @JsonProperty("assumptionValue") + @NotNull + @Size(min = 2, max = 256) + private String assumptionValue = null; + + @JsonProperty("output") + @NotNull + @Size(min = 1, max = 64) + private String output = null; + + @JsonProperty("active") + @NotNull + private Boolean active = true; + + /** + * The operator used in the operation + */ + public enum OperatorEnum { + PLUS("+"), + + MINUS("-"), + + SLASH("/"), + + STAR("*"), + + PERCENT("%"), + + _U("**"); + + private String value; + + OperatorEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static OperatorEnum fromValue(String text) { + for (OperatorEnum b : OperatorEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + text + "'"); + } + } + +} 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 new file mode 100644 index 00000000000..f1fb59a400e --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/Plan.java @@ -0,0 +1,64 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +import jakarta.validation.Valid; +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; + +/** + * Plan + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Plan { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("locality") + @Size(min = 1, max = 64) + private String locality = null; + + @JsonProperty("executionPlanId") + @Size(max = 64) + private String executionPlanId = null; + + @JsonProperty("planConfigurationId") + @Size(max = 64) + private String planConfigurationId = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("activities") + @Valid + private List activities; + + @JsonProperty("resources") + @Valid + private List resources; + + @JsonProperty("targets") + @Valid + private List targets; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + +} 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 new file mode 100644 index 00000000000..dbf9ed7f139 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanConfiguration.java @@ -0,0 +1,91 @@ +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; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import jakarta.validation.constraints.Pattern; +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * PlanConfiguration + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanConfiguration { + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("name") + @NotNull + @Size(min = 2, max = 128) + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Name must not contain only special characters") + private String name = null; + + @JsonProperty("executionPlanId") + @NotNull + @Size(min = 2, max = 64) + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Execution Plan Id must not contain only special characters") + private String executionPlanId = null; + + @JsonProperty("status") + @NotNull + private StatusEnum status = null; + + @JsonProperty("files") + @NotNull + @NotEmpty + @Valid + private List files = new ArrayList<>(); + + @JsonProperty("assumptions") + @NotNull + @NotEmpty + @Valid + private List assumptions = new ArrayList<>(); + + @JsonProperty("operations") + @NotNull + @NotEmpty + @Valid + private List operations = new ArrayList<>(); + + @JsonProperty("resourceMapping") + @NotNull + @NotEmpty + @Valid + private List resourceMapping = new ArrayList<>(); + + @JsonProperty("auditDetails") + private @Valid AuditDetails auditDetails; + + /** + * The status used in the Plan Configuration + */ + public enum StatusEnum { + DRAFT , + GENERATED, + INVALID_DATA + } + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationRequest.java b/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationRequest.java new file mode 100644 index 00000000000..4636259bde7 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationRequest.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; + +/** + * PlanConfigurationRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanConfigurationRequest { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("PlanConfiguration") + @Valid + private PlanConfiguration planConfiguration = null; + + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationResponse.java b/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationResponse.java new file mode 100644 index 00000000000..e374ea5ea43 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationResponse.java @@ -0,0 +1,43 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.ArrayList; +import java.util.List; +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; + +/** + * PlanConfigurationResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanConfigurationResponse { + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("PlanConfiguration") + @Valid + private List planConfiguration = null; + + @JsonProperty("TotalCount") + @Valid + private Integer totalCount = null; + + public PlanConfigurationResponse addPlanConfigurationResponseItem(PlanConfiguration planConfigurationResponseItem) { + if (this.planConfiguration == null) { + this.planConfiguration = new ArrayList<>(); + } + this.planConfiguration.add(planConfigurationResponseItem); + return this; + } + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationSearchCriteria.java b/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationSearchCriteria.java new file mode 100644 index 00000000000..ab7c827c49a --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationSearchCriteria.java @@ -0,0 +1,54 @@ +package digit.web.models; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.springframework.validation.annotation.Validated; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * PlanConfigurationSearchCriteria + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanConfigurationSearchCriteria { + + @JsonProperty("tenantId") + @Size(min = 2, max = 256) + @NotNull + private String tenantId = null; + + @JsonProperty("id") + private String id = null; + + @JsonProperty("name") + private String name = null; + + @JsonProperty("executionPlanId") + private String executionPlanId = null; + + @JsonProperty("status") + private String status = null; + + @JsonProperty("userUuid") + private String userUuid = null; + + @JsonProperty("offset") + @Min(0) + private Integer offset; + + @JsonProperty("limit") + @Min(1) + @Max(50) + private Integer limit; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationSearchRequest.java b/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationSearchRequest.java new file mode 100644 index 00000000000..11874e2a600 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanConfigurationSearchRequest.java @@ -0,0 +1,30 @@ +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; + +/** + * PlanConfigurationSearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanConfigurationSearchRequest { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("PlanConfigurationSearchCriteria") + @Valid + private PlanConfigurationSearchCriteria planConfigurationSearchCriteria = null; + + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanRequest.java b/health-services/plan-service/src/main/java/digit/web/models/PlanRequest.java new file mode 100644 index 00000000000..cf3fd8bfcc8 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanRequest.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; + +/** + * PlanCreateRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanRequest { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Plan") + @Valid + private Plan plan = null; + + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/PlanResponse.java b/health-services/plan-service/src/main/java/digit/web/models/PlanResponse.java new file mode 100644 index 00000000000..bf08ba0059c --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanResponse.java @@ -0,0 +1,31 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +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; + +/** + * PlanSearchResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Plan") + @Valid + private List plan = 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 new file mode 100644 index 00000000000..6e9cc9449d1 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanSearchCriteria.java @@ -0,0 +1,46 @@ +package digit.web.models; + +import java.util.Set; + +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.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * 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 String locality = null; + + @JsonProperty("executionPlanId") + private String executionPlanId = null; + + @JsonProperty("planConfigurationId") + private String planConfigurationId = null; + + @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/PlanSearchRequest.java b/health-services/plan-service/src/main/java/digit/web/models/PlanSearchRequest.java new file mode 100644 index 00000000000..05847584439 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/PlanSearchRequest.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; + +/** + * 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/plan-service/src/main/java/digit/web/models/Resource.java b/health-services/plan-service/src/main/java/digit/web/models/Resource.java new file mode 100644 index 00000000000..0b64b3108c1 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/Resource.java @@ -0,0 +1,39 @@ +package digit.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.math.BigDecimal; +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; + +/** + * Resource + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Resource { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("resourceType") + @NotNull + @Size(min = 2, max = 256) + private String resourceType = null; + + @JsonProperty("estimatedNumber") + @NotNull + private BigDecimal estimatedNumber = null; + + @JsonProperty("activityCode") + @Size(min = 2, max = 128) + private String activityCode = null; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/ResourceMapping.java b/health-services/plan-service/src/main/java/digit/web/models/ResourceMapping.java new file mode 100644 index 00000000000..0b3cd72b606 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/ResourceMapping.java @@ -0,0 +1,48 @@ +package digit.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.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * ResourceMapping + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ResourceMapping { + @JsonProperty("id") + @Valid + private String id = null; + + @JsonProperty("filestoreId") + @NotNull + @Size(min = 1, max = 128) + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Filestore Id must not contain only special characters") + private String filestoreId = null; + + @JsonProperty("mappedFrom") + @NotNull + @Size(min = 2, max = 256) + private String mappedFrom = null; + + @JsonProperty("mappedTo") + @NotNull + @Size(min = 2, max = 256) + private String mappedTo = null; + + @JsonProperty("active") + @NotNull + private Boolean active = true; + +} diff --git a/health-services/plan-service/src/main/java/digit/web/models/Target.java b/health-services/plan-service/src/main/java/digit/web/models/Target.java new file mode 100644 index 00000000000..ad8bbfa5173 --- /dev/null +++ b/health-services/plan-service/src/main/java/digit/web/models/Target.java @@ -0,0 +1,37 @@ +package digit.web.models; + +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.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * Target + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Target { + + @JsonProperty("id") + @Valid + private String id = null; + + @JsonProperty("metric") + private String metric = null; + + @JsonProperty("metricDetail") + @Valid + private MetricDetail metricDetail = null; + + @JsonProperty("activityCode") + @Size(min = 2, max = 128) + private String activityCode = null; + +} diff --git a/health-services/plan-service/src/main/resources/application.properties b/health-services/plan-service/src/main/resources/application.properties new file mode 100644 index 00000000000..03ee3da916d --- /dev/null +++ b/health-services/plan-service/src/main/resources/application.properties @@ -0,0 +1,61 @@ +server.port=8080 +server.servlet.context-path=/plan-service + +#MANAGEMENT ENDPOINT CONFIGURATION +management.endpoints.web.base-path=/ +app.timezone=UTC + +#DATABASE CONFIGURATION +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/plandb +spring.datasource.username=postgres +spring.datasource.password=postgres + +#FLYWAY CONFIGURATION +spring.flyway.url=jdbc:postgresql://localhost:5432/plandb +spring.flyway.user=postgres +spring.flyway.password=postgres +spring.flyway.table=public +spring.flyway.baseline-on-migrate=true +spring.flyway.outOfOrder=true +spring.flyway.locations=classpath:/db/migration/main +spring.flyway.enabled=false + +# KAFKA SERVER CONFIGURATIONS +kafka.config.bootstrap_server_config=localhost:9092 +spring.kafka.consumer.value-deserializer=org.egov.tracer.kafka.deserializer.HashMapDeserializer +spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer +spring.kafka.consumer.group-id=plan-service +spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer +spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer +spring.kafka.listener.missing-topics-fatal=false +spring.kafka.consumer.properties.spring.json.use.type.headers=false + +# KAFKA CONSUMER CONFIGURATIONS +kafka.consumer.config.auto_commit=true +kafka.consumer.config.auto_commit_interval=100 +kafka.consumer.config.session_timeout=15000 +kafka.consumer.config.auto_offset_reset=earliest +# KAFKA PRODUCER CONFIGURATIONS +kafka.producer.config.retries_config=0 +kafka.producer.config.batch_size_config=16384 +kafka.producer.config.linger_ms_config=1 +kafka.producer.config.buffer_memory_config=33554432 + +# PERSISTER KAFKA TOPICS +plan.configuration.create.topic=plan-config-create-topic +plan.configuration.update.topic=plan-config-update-topic + +plan.create.topic=save-plan +plan.update.topic=update-plan + +#mdms urls +egov.mdms.host=https://unified-dev.digit.org +egov.mdms.search.endpoint=/egov-mdms-service/v1/_search + +# Pagination config +plan.default.offset=0 +plan.default.limit=10 + +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 diff --git a/health-services/plan-service/src/main/resources/db/Dockerfile b/health-services/plan-service/src/main/resources/db/Dockerfile new file mode 100644 index 00000000000..60fc07ce69f --- /dev/null +++ b/health-services/plan-service/src/main/resources/db/Dockerfile @@ -0,0 +1,9 @@ +FROM egovio/flyway:4.1.2 + +COPY ./migration/main /flyway/sql + +COPY migrate.sh /usr/bin/migrate.sh + +RUN chmod +x /usr/bin/migrate.sh + +CMD ["/usr/bin/migrate.sh"] \ No newline at end of file diff --git a/health-services/plan-service/src/main/resources/db/migrate.sh b/health-services/plan-service/src/main/resources/db/migrate.sh new file mode 100644 index 00000000000..43960b25cdb --- /dev/null +++ b/health-services/plan-service/src/main/resources/db/migrate.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS -baselineOnMigrate=true -outOfOrder=true -ignoreMissingMigrations=true migrate \ No newline at end of file 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 new file mode 100644 index 00000000000..e9630421bcb --- /dev/null +++ b/health-services/plan-service/src/main/resources/db/migration/main/V20240305113045__plan_configuration_create_ddl.sql @@ -0,0 +1,73 @@ +-- 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), + created_by character varying(64), + created_time bigint, + last_modified_by character varying(64), + last_modified_time bigint, + CONSTRAINT uk_plan_configuration_id PRIMARY KEY (id) +); + + +-- Table: plan_configuration_files +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), + created_by character varying(64), + created_time bigint, + last_modified_by character varying(64), + last_modified_time bigint, + CONSTRAINT uk_plan_configuration_files_id PRIMARY KEY (id), + FOREIGN KEY (plan_configuration_id) REFERENCES plan_configuration(id) +); + + +-- Table: plan_configuration_assumptions +CREATE TABLE plan_configuration_assumptions ( + id character varying(64), + key character varying(256), + value numeric(12,2), + plan_configuration_id character varying(64), + created_by character varying(64), + created_time bigint, + last_modified_by character varying(64), + last_modified_time bigint, + CONSTRAINT uk_plan_configuration_assumptions_id PRIMARY KEY (id), + FOREIGN KEY (plan_configuration_id) REFERENCES plan_configuration(id) +); + + +-- 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), + plan_configuration_id character varying(64), + created_by character varying(64), + created_time bigint, + last_modified_by character varying(64), + last_modified_time bigint, + CONSTRAINT uk_plan_configuration_operations_id PRIMARY KEY (id), + FOREIGN KEY (plan_configuration_id) REFERENCES plan_configuration(id) +); + + +-- Table: plan_configuration_mapping +CREATE TABLE plan_configuration_mapping ( + id character varying(64), + mapped_from character varying(256), + mapped_to character varying(256), + plan_configuration_id character varying(64), + created_by character varying(64), + created_time bigint, + last_modified_by character varying(64), + last_modified_time bigint, + CONSTRAINT uk_plan_configuration_mapping_id PRIMARY KEY (id) +); \ No newline at end of file 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 new file mode 100644 index 00000000000..942cc36af38 --- /dev/null +++ b/health-services/plan-service/src/main/resources/db/migration/main/V20240305113047__plan_create_ddl.sql @@ -0,0 +1,74 @@ +CREATE TABLE plan ( + id varchar(64), + tenant_id varchar(64), + locality varchar(64), + execution_plan_id varchar(64), + plan_configuration_id varchar(64), + additional_details JSONB, + created_by varchar(64), + created_time bigint, + last_modified_by varchar(64), + last_modified_time bigint, + CONSTRAINT uk_plan_id PRIMARY KEY (id) +); + +CREATE TABLE plan_activity ( + id varchar(64) NOT NULL, + code varchar(128) NOT NULL, + description varchar(2048), + planned_start_date bigint, + planned_end_date bigint, + dependencies character varying(2048), + plan_id varchar(64) NOT NULL, + created_by varchar(64), + created_time bigint, + last_modified_by varchar(64), + last_modified_time bigint, + CONSTRAINT uk_plan_activity_id PRIMARY KEY (id), + FOREIGN KEY (plan_id) REFERENCES plan(id) +); + +CREATE TABLE plan_activity_condition ( + id varchar(64), + entity varchar(64), + entity_property varchar(64), + expression varchar(2048), + activity_id varchar(64), + is_active boolean DEFAULT true, + created_by varchar(64), + created_time bigint, + last_modified_by varchar(64), + last_modified_time bigint, + CONSTRAINT uk_plan_activity_condition_id PRIMARY KEY (id), + FOREIGN KEY (activity_id) REFERENCES plan_activity(id) +); + +CREATE TABLE plan_resource ( + id varchar(64), + resource_type varchar(256), + estimated_number numeric(12,2), + plan_id varchar(64), + activity_code varchar(128), + created_by varchar(64), + created_time bigint, + last_modified_by varchar(64), + last_modified_time bigint, + CONSTRAINT uk_plan_resource_id PRIMARY KEY (id), + FOREIGN KEY (plan_id) REFERENCES plan(id) +); + +CREATE TABLE plan_target ( + id varchar(64), + metric varchar(128), + metric_value numeric(12,2), + metric_comparator varchar(64), + metric_unit varchar(128), + plan_id varchar(64), + activity_code varchar(128), + created_by varchar(64), + created_time bigint, + last_modified_by varchar(64), + last_modified_time bigint, + CONSTRAINT uk_plan_target_id PRIMARY KEY (id), + FOREIGN KEY (plan_id) REFERENCES plan(id) +); \ No newline at end of file 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 new file mode 100644 index 00000000000..fcd7cfe2bbc --- /dev/null +++ b/health-services/plan-service/src/main/resources/db/migration/main/V20240404113045__plan_configuration_add_filestoreid_ddl.sql @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000000..e1c67ff2696 --- /dev/null +++ b/health-services/plan-service/src/main/resources/db/migration/main/V20240404150000__plan_configuration_add_template_identifier_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE plan_configuration_files ADD template_identifier character varying(128); 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 new file mode 100644 index 00000000000..8683e34faef --- /dev/null +++ b/health-services/plan-service/src/main/resources/db/migration/main/V20241604150000__plan_configuration_add_status_ddl.sql @@ -0,0 +1,2 @@ +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 new file mode 100644 index 00000000000..3586cd4cb45 --- /dev/null +++ b/health-services/plan-service/src/main/resources/db/migration/main/V20242105150000__plan_configuration_add_active_ddl.sql @@ -0,0 +1,11 @@ +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/test/java/digit/TestConfiguration.java b/health-services/plan-service/src/test/java/digit/TestConfiguration.java new file mode 100644 index 00000000000..570236cfc94 --- /dev/null +++ b/health-services/plan-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/plan-service/src/test/java/digit/web/controllers/CreateApiControllerTest.java b/health-services/plan-service/src/test/java/digit/web/controllers/CreateApiControllerTest.java new file mode 100644 index 00000000000..0826f5c88f6 --- /dev/null +++ b/health-services/plan-service/src/test/java/digit/web/controllers/CreateApiControllerTest.java @@ -0,0 +1,43 @@ +package digit.web.controllers; + +import org.junit.Test; +import org.junit.Ignore; +import org.junit.runner.RunWith; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.context.annotation.Import; +import org.springframework.http.HttpStatus; +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 CreateApiController +*/ +@Ignore +@RunWith(SpringRunner.class) +@WebMvcTest(PlanController.class) +@Import(TestConfiguration.class) +public class CreateApiControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void createPostSuccess() throws Exception { + mockMvc.perform(post("/plan/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void createPostFailure() throws Exception { + mockMvc.perform(post("/plan/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + +} diff --git a/health-services/plan-service/src/test/java/digit/web/controllers/PlanConfigControllerTest.java b/health-services/plan-service/src/test/java/digit/web/controllers/PlanConfigControllerTest.java new file mode 100644 index 00000000000..03fbbd0c8ed --- /dev/null +++ b/health-services/plan-service/src/test/java/digit/web/controllers/PlanConfigControllerTest.java @@ -0,0 +1,71 @@ +package digit.web.controllers; + +import org.junit.Test; +import org.junit.Ignore; +import org.junit.runner.RunWith; +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 ConfigApiController +*/ +@Ignore +@RunWith(SpringRunner.class) +@WebMvcTest(PlanConfigController.class) +@Import(TestConfiguration.class) +public class PlanConfigControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void configCreatePostSuccess() throws Exception { + mockMvc.perform(post("/plan/config/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void configCreatePostFailure() throws Exception { + mockMvc.perform(post("/plan/config/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + + @Test + public void configSearchPostSuccess() throws Exception { + mockMvc.perform(post("/plan/config/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void configSearchPostFailure() throws Exception { + mockMvc.perform(post("/plan/config/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + + @Test + public void configUpdatePostSuccess() throws Exception { + mockMvc.perform(post("/plan/config/_update").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void configUpdatePostFailure() throws Exception { + mockMvc.perform(post("/plan/config/_update").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + +} diff --git a/health-services/product/CHANGELOG.md b/health-services/product/CHANGELOG.md index a27826b5875..6a3ffe49450 100644 --- a/health-services/product/CHANGELOG.md +++ b/health-services/product/CHANGELOG.md @@ -1,5 +1,8 @@ +# CHANGELOG All notable changes to this module will be documented in this file. ## 1.0.0 -- Base version \ No newline at end of file +- Base version + +## 1.1.0 \ No newline at end of file diff --git a/health-services/product/pom.xml b/health-services/product/pom.xml index f8deef3778e..bb11e8702d6 100644 --- a/health-services/product/pom.xml +++ b/health-services/product/pom.xml @@ -5,7 +5,7 @@ product jar product - 1.0.0 + 1.1.0 1.8 ${java.version} @@ -44,11 +44,12 @@ org.flywaydb flyway-core + 9.22.3 org.postgresql postgresql - 42.2.2.jre7 + 42.7.1 org.springframework.boot @@ -80,7 +81,7 @@ org.egov.common health-services-models - 1.0.0-SNAPSHOT + 1.0.7-SNAPSHOT compile diff --git a/health-services/product/src/main/resources/db/Dockerfile b/health-services/product/src/main/resources/db/Dockerfile index 60fc07ce69f..e7da01d7f0b 100644 --- a/health-services/product/src/main/resources/db/Dockerfile +++ b/health-services/product/src/main/resources/db/Dockerfile @@ -1,4 +1,4 @@ -FROM egovio/flyway:4.1.2 +FROM egovio/flyway:10.7.1 COPY ./migration/main /flyway/sql @@ -6,4 +6,4 @@ COPY migrate.sh /usr/bin/migrate.sh RUN chmod +x /usr/bin/migrate.sh -CMD ["/usr/bin/migrate.sh"] \ No newline at end of file +ENTRYPOINT ["/usr/bin/migrate.sh"] \ No newline at end of file diff --git a/health-services/product/src/main/resources/db/migrate.sh b/health-services/product/src/main/resources/db/migrate.sh index 43960b25cdb..f9d6617822c 100644 --- a/health-services/product/src/main/resources/db/migrate.sh +++ b/health-services/product/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/project-factory/.gitignore b/health-services/project-factory/.gitignore new file mode 100644 index 00000000000..29554b428f0 --- /dev/null +++ b/health-services/project-factory/.gitignore @@ -0,0 +1,120 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +.vscode/ + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +dist/ +jspm_packages/ + +.bin/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.pnp.* \ No newline at end of file diff --git a/health-services/project-factory/CHANGELOG.md b/health-services/project-factory/CHANGELOG.md new file mode 100644 index 00000000000..8781f319963 --- /dev/null +++ b/health-services/project-factory/CHANGELOG.md @@ -0,0 +1,16 @@ +# Changelog +All notable changes to this module will be documented in this file. + +## 0.1.0 - 2024-05-28 +#### Base ProjectFactory service + 1. ProjectFactory Service manages campaigns: creation, updating, searching, and data generation. + 2. Project Mapping : In campaign creation full project mapping is done with staff, facility and resources along with proper target values. + 3. Create Data: Validates and creates resource details of type facility,user and boundary. + 4. Generate Data: Generates sheet data of type facility,user and boundary. + 5. Boundary and Resource Validation: Validates boundaries and resources during campaign creation and updating. + +## 0.2.0 - 2024-08-7 +#### ProjectFactory service version 0.2 + 1. Timeline integration for workflow of campaign. + 2. Call user, facility and boundary generate when boundaries changed in campaign update flow + 3. Generate target template based on delivery conditions changed to anything from default. diff --git a/health-services/project-factory/Dockerfile b/health-services/project-factory/Dockerfile new file mode 100644 index 00000000000..124ed02c197 --- /dev/null +++ b/health-services/project-factory/Dockerfile @@ -0,0 +1,34 @@ +# Use Node.js base image with version 16 +FROM node:20 AS build + +# Set working directory +WORKDIR /app + +# Set build arguments +ARG BRANCH_NAME +ARG ACTION_NUMBER +ARG COMMIT_ID + +# Set environment variables based on build arguments +ENV BRANCH_NAME=$BRANCH_NAME +ENV ACTION_NUMBER=$ACTION_NUMBER +ENV COMMIT_ID=$COMMIT_ID + +# Copy package.json and yarn.lock (if exists) +COPY package.json ./ + +# Install dependencies +RUN yarn install + +# Optionally, you can add a label with the commit ID +LABEL commit_id=$COMMIT_ID + +# Copy the rest of the application code +COPY . . + +# Expose the port your app runs on +EXPOSE 3000 + +CMD ["yarn", "prod"] + # Replace "app.js" with your entry point file + diff --git a/health-services/project-factory/LICENSE b/health-services/project-factory/LICENSE new file mode 100644 index 00000000000..a0f698ede23 --- /dev/null +++ b/health-services/project-factory/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Jagankumar E + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/health-services/project-factory/LOCALSETUP.md b/health-services/project-factory/LOCALSETUP.md new file mode 100644 index 00000000000..3417b07ccd7 --- /dev/null +++ b/health-services/project-factory/LOCALSETUP.md @@ -0,0 +1,32 @@ +# Local Setup + +To set up the ProjectFactory service in your local system, clone the [Digit Frontend repository](https://github.com/egovernments/DIGIT-Frontend). + +## Dependencies + +### Infra Dependency + +- [x] Postgres DB +- [ ] Redis +- [ ] Elasticsearch +- [x] Kafka + - [x] Consumer + - [x] Producer + +## Running Locally + +### Local setup +1. To setup the ProjectFactory service, clone the [Digit Frontend repository](https://github.com/egovernments/DIGIT-Frontend). +2. Install Node.js version 20 using nvm (Node Version Manager). +3. Update the configs in [utilities/project-factory/src/server/config/index.ts](utilities/project-factory/src/server/config/index.ts), change HOST to "http://localhost:8080/" and KAFKA_BROKER_HOST to "localhost:9092". +4. Also update DB config values as per your local system config. +5. Update all dependency service host either on any unified-env or port-forward. +6. Open the terminal and run the following command + + `cd utilities/project-factory/` + + `yarn install` (run this command only once when you clone the repo) + + `yarn dev` + +> Note: After running the above command, if a Kafka error occurs, ensure that Kafka and Zookeeper are running in the background. If a connection error with another microservice occurs, ensure that the URL mentioned in the external mapping of the data config is correct, or you can port-forward that particular service. diff --git a/health-services/project-factory/README.md b/health-services/project-factory/README.md new file mode 100644 index 00000000000..0b545626fe6 --- /dev/null +++ b/health-services/project-factory/README.md @@ -0,0 +1,93 @@ +# ProjectFactory Service + +The **ProjectFactory Service** is responsible for managing project-type campaigns, including creating, updating, searching, and generating campaign data. + +## DB UML Diagram + +![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 + +### Core Services + +- `egov-localization` +- `egov-filestore` +- `egov-persister` +- `egov-mdms` +- `egov-idgen` +- `egov-boundaryservice-v2` + +### Health Services + +- `health-project` +- `health-hrms` +- `health-facility` + +### 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 + +### 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. +- **[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) + +## 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. + +## Kafka Consumers + +- **`start-campaign-mapping`**: Initiates the mapping process for campaigns. + +## Kafka Producers + +- **`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. + +## Redis Caching + +- **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/Dockerfile b/health-services/project-factory/migration/Dockerfile new file mode 100644 index 00000000000..1761f250c73 --- /dev/null +++ b/health-services/project-factory/migration/Dockerfile @@ -0,0 +1,9 @@ +FROM egovio/flyway:10.7.1 + +COPY ./main /flyway/sql + +COPY migrate.sh /usr/bin/migrate.sh + +RUN chmod +x /usr/bin/migrate.sh + +ENTRYPOINT ["/usr/bin/migrate.sh"] \ No newline at end of file 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 new file mode 100644 index 00000000000..aecfae20001 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240315110400__resource_details_ddl.sql @@ -0,0 +1,46 @@ +CREATE TABLE eg_cm_resource_details ( + id varchar(128) PRIMARY KEY, + "status" varchar(128) NOT NULL, + tenantId varchar(128) NOT NULL, + fileStoreId varchar(128) NOT NULL, + processedFileStoreId varchar(128), + "action" varchar(128) NOT NULL, + "type" varchar(64) NOT NULL, + createdBy varchar(128) NOT NULL, + createdTime bigint NOT NULL, + lastModifiedBy varchar(128), + lastModifiedTime bigint, + additionalDetails jsonb +); + +CREATE TABLE eg_cm_resource_activity ( + id varchar(128) PRIMARY KEY, + retryCount integer, + "type" varchar(64), + "url" varchar(128), + requestPayload jsonb, + tenantId varchar(128) NOT NULL, + responsePayload jsonb, + "status" bigint, + createdBy varchar(128), + createdTime bigint, + lastModifiedBy varchar(128), + lastModifiedTime bigint, + additionalDetails jsonb, + resourceDetailsId varchar(128), + FOREIGN KEY (resourceDetailsId) REFERENCES eg_cm_resource_details(id) +); + +CREATE TABLE eg_cm_generated_resource_details ( + id varchar(128) PRIMARY KEY, + fileStoreId varchar(128), + "status" varchar(128), + "type" varchar(128), + tenantid varchar(128), + count bigint, + createdBy varchar(128), + createdTime bigint, + lastModifiedBy varchar(128), + lastModifiedTime bigint, + additionalDetails jsonb +); diff --git a/health-services/project-factory/migration/main/V20240315110513__campaign_details_ddl.sql b/health-services/project-factory/migration/main/V20240315110513__campaign_details_ddl.sql new file mode 100644 index 00000000000..1f6426149f5 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240315110513__campaign_details_ddl.sql @@ -0,0 +1,16 @@ +CREATE TABLE eg_cm_campaign_details ( + id character varying(128) PRIMARY KEY, + tenantId character varying(64) NOT NULL, + "status" character varying(128) NOT NULL, + "action" character varying(64) NOT NULL, + campaignNumber character varying(128) NOT NULL, + hierarchyType character varying(128) NOT NULL, + boundaryCode character varying(64), + projectId character varying(128), + createdBy character varying(128) NOT NULL, + lastModifiedBy character varying(128), + createdTime bigint NOT NULL, + lastModifiedTime bigint, + additionalDetails jsonb, + campaignDetails jsonb +); diff --git a/health-services/project-factory/migration/main/V20240401154500__campaign_details_add_columns.sql b/health-services/project-factory/migration/main/V20240401154500__campaign_details_add_columns.sql new file mode 100644 index 00000000000..eaf0c681333 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240401154500__campaign_details_add_columns.sql @@ -0,0 +1,3 @@ +ALTER TABLE eg_cm_campaign_details +ADD COLUMN campaignName character varying(128) UNIQUE, +ADD COLUMN projectType character varying(128); diff --git a/health-services/project-factory/migration/main/V20240402134500__campaign_details_alter_column.sql b/health-services/project-factory/migration/main/V20240402134500__campaign_details_alter_column.sql new file mode 100644 index 00000000000..7a49127c9dd --- /dev/null +++ b/health-services/project-factory/migration/main/V20240402134500__campaign_details_alter_column.sql @@ -0,0 +1,2 @@ +ALTER TABLE eg_cm_campaign_details +ALTER COLUMN hierarchyType DROP NOT NULL; diff --git a/health-services/project-factory/migration/main/V20240410154500__campaign_details_alter_column.sql b/health-services/project-factory/migration/main/V20240410154500__campaign_details_alter_column.sql new file mode 100644 index 00000000000..05dfea2b5c7 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240410154500__campaign_details_alter_column.sql @@ -0,0 +1,3 @@ +ALTER TABLE eg_cm_campaign_details +ADD COLUMN startDate bigint, +ADD COLUMN endDate bigint; \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240416170000__generate_add_column.sql b/health-services/project-factory/migration/main/V20240416170000__generate_add_column.sql new file mode 100644 index 00000000000..c96caaa0e5f --- /dev/null +++ b/health-services/project-factory/migration/main/V20240416170000__generate_add_column.sql @@ -0,0 +1,2 @@ +ALTER TABLE eg_cm_generated_resource_details +ADD COLUMN hierarchyType varchar(128); \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240427174100__campaign_add_column.sql b/health-services/project-factory/migration/main/V20240427174100__campaign_add_column.sql new file mode 100644 index 00000000000..36707083732 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240427174100__campaign_add_column.sql @@ -0,0 +1,2 @@ +ALTER TABLE eg_cm_campaign_details +ALTER COLUMN campaignName TYPE character varying(250); \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240522143500__resource_details_alter_column.sql b/health-services/project-factory/migration/main/V20240522143500__resource_details_alter_column.sql new file mode 100644 index 00000000000..25fc10438f1 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240522143500__resource_details_alter_column.sql @@ -0,0 +1,2 @@ +ALTER TABLE eg_cm_resource_details +ADD COLUMN campaignId character varying(128); \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240624210000__generated_resource_details_alter_column.sql b/health-services/project-factory/migration/main/V20240624210000__generated_resource_details_alter_column.sql new file mode 100644 index 00000000000..dfd13713c78 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240624210000__generated_resource_details_alter_column.sql @@ -0,0 +1,13 @@ +DO $$ +DECLARE + table_name1 TEXT := 'eg_cm_generated_resource_details'; + column_name1 TEXT := 'campaignId'; +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = table_name1 + AND column_name = column_name1 + ) THEN + EXECUTE format('ALTER TABLE %I ADD COLUMN %I character varying(128);', table_name1, column_name1); + END IF; +END $$; \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240625141100__process_details_ddl.sql b/health-services/project-factory/migration/main/V20240625141100__process_details_ddl.sql new file mode 100644 index 00000000000..e7b4037bd8d --- /dev/null +++ b/health-services/project-factory/migration/main/V20240625141100__process_details_ddl.sql @@ -0,0 +1,11 @@ +CREATE TABLE health.eg_cm_campaign_process ( + id VARCHAR(128) PRIMARY KEY, + campaignId VARCHAR(128) NOT NULL, + type VARCHAR(128), + status VARCHAR(128), + details JSONB, + createdtime BIGINT, + lastmodifiedtime BIGINT, + additionaldetails JSONB, + CONSTRAINT fk_campaignId FOREIGN KEY (campaignId) REFERENCES health.eg_cm_campaign_details(id) +); diff --git a/health-services/project-factory/migration/main/V20240708153000__generated_resource_detail_alter_column.sql b/health-services/project-factory/migration/main/V20240708153000__generated_resource_detail_alter_column.sql new file mode 100644 index 00000000000..a67a8061f42 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240708153000__generated_resource_detail_alter_column.sql @@ -0,0 +1,24 @@ +DO $$ +DECLARE + table_name1 TEXT := 'eg_cm_generated_resource_details'; + column_name1 TEXT := 'campaignId'; + column_name2 TEXT := 'campaignid'; +BEGIN + -- Check if "campaignId" column exists and drop it if it does + IF EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = table_name1 + AND column_name = column_name1 + ) THEN + EXECUTE format('ALTER TABLE %I DROP COLUMN %I;', table_name1, column_name1); + END IF; + + -- Check if "campaignid" column exists (case-insensitive) and create it if it doesn't + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = table_name1 + AND lower(column_name) = lower(column_name2) + ) THEN + EXECUTE format('ALTER TABLE %I ADD COLUMN %I character varying(128);', table_name1, column_name2); + END IF; +END $$; diff --git a/health-services/project-factory/migration/main/V20240725155100__remove_constraint_process_details.sql b/health-services/project-factory/migration/main/V20240725155100__remove_constraint_process_details.sql new file mode 100644 index 00000000000..9142fc152e0 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240725155100__remove_constraint_process_details.sql @@ -0,0 +1,3 @@ +-- Migration script to remove the foreign key constraint +ALTER TABLE eg_cm_campaign_process DROP CONSTRAINT IF EXISTS fk_campaignId; +ALTER TABLE eg_cm_resource_activity DROP CONSTRAINT IF EXISTS eg_cm_resource_activity_resourceDetailsId_fkey; \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240731162600__add_uniqiue_constraint_process_track.sql b/health-services/project-factory/migration/main/V20240731162600__add_uniqiue_constraint_process_track.sql new file mode 100644 index 00000000000..d9bfbd0af53 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240731162600__add_uniqiue_constraint_process_track.sql @@ -0,0 +1,10 @@ +-- Step 1: Remove duplicate rows +DELETE FROM eg_cm_campaign_process a +USING health.eg_cm_campaign_process b +WHERE a.id < b.id +AND a.campaignId = b.campaignId +AND a.type = b.type; + +-- Step 2: Add the unique constraint +ALTER TABLE eg_cm_campaign_process +ADD CONSTRAINT uq_campaignId_type UNIQUE (campaignId, type); diff --git a/health-services/project-factory/migration/migrate.sh b/health-services/project-factory/migration/migrate.sh new file mode 100755 index 00000000000..c433c239956 --- /dev/null +++ b/health-services/project-factory/migration/migrate.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS 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 new file mode 100644 index 00000000000..a7479aa962a --- /dev/null +++ b/health-services/project-factory/package-lock.json @@ -0,0 +1,9560 @@ +{ + "name": "project-factory", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "project-factory", + "version": "0.0.1", + "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", + "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", + "lodash": "4.17.21", + "morgan": "1.10.0", + "node-cache": "5.1.2", + "node-gyp": "10.0.1", + "opentracing": "^0.14.7", + "uuid": "9.0.1", + "winston": "3.12.0", + "xlsx": "0.18.5", + "xlsx-populate": "1.21.0", + "yup": "1.4.0" + }, + "devDependencies": { + "@types/compression": "1.7.5", + "@types/express": "4.17.21", + "@types/hash-sum": "1.0.2", + "@types/helmet": "0.0.47", + "@types/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", + "@types/uuid": "9.0.8", + "@types/xlsx": "0.0.36", + "ajv": "^8.16.0", + "eslint": "7.16.0", + "jest": "29.7.0", + "pg": "8.12.0", + "ts-node-dev": "2.0.0", + "typescript": "5.4.2" + } + }, + "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, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz", + "integrity": "sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.24.5", + "@babel/helpers": "^7.24.5", + "@babel/parser": "^7.24.5", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.5", + "@babel/types": "^7.24.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "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, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz", + "integrity": "sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.5", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/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, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "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, + "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, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz", + "integrity": "sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.24.3", + "@babel/helper-simple-access": "^7.24.5", + "@babel/helper-split-export-declaration": "^7.24.5", + "@babel/helper-validator-identifier": "^7.24.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz", + "integrity": "sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz", + "integrity": "sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz", + "integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz", + "integrity": "sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==", + "dev": true, + "dependencies": { + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.5", + "@babel/types": "^7.24.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", + "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.5", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "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, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz", + "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", + "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz", + "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dev": true, + "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/traverse": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz", + "integrity": "sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.24.5", + "@babel/parser": "^7.24.5", + "@babel/types": "^7.24.5", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/types": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz", + "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.24.1", + "@babel/helper-validator-identifier": "^7.24.5", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "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==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", + "integrity": "sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@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==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "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", + "integrity": "sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==", + "dependencies": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isboolean": "^3.0.3", + "lodash.isequal": "^4.5.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0" + } + }, + "node_modules/@fast-csv/format/node_modules/@types/node": { + "version": "14.18.63", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==" + }, + "node_modules/@fast-csv/parse": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz", + "integrity": "sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==", + "dependencies": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.groupby": "^4.6.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0", + "lodash.isundefined": "^3.0.1", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/@fast-csv/parse/node_modules/@types/node": { + "version": "14.18.63", + "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==", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "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==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-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, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/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, + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/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/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "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 + }, + "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, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@npmcli/agent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", + "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/fs": { + "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" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/fs/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "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, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "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 + }, + "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 + }, + "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 + }, + "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, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", + "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/compression": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz", + "integrity": "sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz", + "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-UP28RddqY8xcU0SCEp9YKutQICXpaAq9N8U2klqF5hegGha7KzTOL8EdhIIV3bOSGBzjEpN9bU/d+nNZBdJYVw==", + "dev": true + }, + "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, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "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==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-proxy-middleware": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/http-proxy-middleware/-/http-proxy-middleware-1.0.0.tgz", + "integrity": "sha512-/s8lFX6rT43hSPqjjD8KNuu0SkPKY7uIdR6u9DCxVqCRhAvfKxGbVOixJsAT2mdpSnCyrGFAGoB39KFh6tmRxw==", + "deprecated": "This is a stub types definition. http-proxy-middleware provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "http-proxy-middleware": "*" + } + }, + "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 + }, + "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, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jaeger-client": { + "version": "3.18.7", + "resolved": "https://registry.npmjs.org/@types/jaeger-client/-/jaeger-client-3.18.7.tgz", + "integrity": "sha512-ktEWbcM8faJY5UNEmffnvavjIJ9noNCD7clD9hAZIuQt6QMv0T97kiveH0mbvBNr9SPZXmkidOu/3UWgSy89tQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "opentracing": "~0.14.3", + "prom-client": "~11.3.0 || ^12.0.0 || ^13.0.0 || ^14.0.0" + } + }, + "node_modules/@types/jest": { + "version": "29.5.12", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", + "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/lodash": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "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, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.11.29", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.29.tgz", + "integrity": "sha512-P99thMkD/1YkCvAtOd6/zGedKNA0p2fj4ZpjCzcNiSCBWgm3cNRTBfa/qjFnsKkkojxu4vVLtWpesnZ9+ap+gA==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/pg": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.3.tgz", + "integrity": "sha512-xocw4LvpDcj/Ta7bN52tLZm34mso5SZ0Q8fVC0UtD8s85Itip3YHvBeYZhBmC0OThpdOujHsxXtRbEIRxqXPXg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^4.0.1" + } + }, + "node_modules/@types/qs": { + "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 + }, + "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, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true + }, + "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 + }, + "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 + }, + "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==" + }, + "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 + }, + "node_modules/@types/xlsx": { + "version": "0.0.36", + "resolved": "https://registry.npmjs.org/@types/xlsx/-/xlsx-0.0.36.tgz", + "integrity": "sha512-mvfrKiKKMErQzLMF8ElYEH21qxWCZtN59pHhWGmWCWFJStYdMWjkDSAy6mGowFxHXaXZWe5/TW7pBUiWclIVOw==", + "deprecated": "This is a stub types definition for xlsx (https://github.com/sheetjs/js-xlsx). xlsx provides its own type definitions, so you don't need @types/xlsx installed!", + "dev": true, + "dependencies": { + "xlsx": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, + "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==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/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==" + }, + "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==", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", + "integrity": "sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==", + "peerDependencies": { + "ajv": "^8.0.1" + } + }, + "node_modules/ansi-color": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-color/-/ansi-color-0.2.1.tgz", + "integrity": "sha512-bF6xLaZBLpOQzgYUtYEhJx090nPSZk1BQ/q2oyBK9aMMcJHzx9uXGCjI2Y+LebsN4Jwoykr0V9whbPiogdyHoQ==", + "engines": { + "node": "*" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "optional": true + }, + "node_modules/archiver": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", + "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^3.2.4", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/archiver/node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "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==", + "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" + } + }, + "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==", + "deprecated": "This package is no longer supported.", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "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, + "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==" + }, + "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, + "engines": { + "node": ">=8" + } + }, + "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/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "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==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "dependencies": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bintrees": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz", + "integrity": "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==", + "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==", + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==" + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "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==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "optional": true, + "dependencies": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "node_modules/buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "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==", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", + "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 + }, + "node_modules/buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/buffermaker": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/buffermaker/-/buffermaker-1.2.1.tgz", + "integrity": "sha512-IdnyU2jDHU65U63JuVQNTHiWjPRH0CS3aYd/WPaEwyX84rFdukhOduAVb1jwUScmb5X0JWPw8NZOrhoLMiyAHQ==", + "dependencies": { + "long": "1.1.2" + } + }, + "node_modules/buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "engines": { + "node": ">=0.2.0" + } + }, + "node_modules/bufrw": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/bufrw/-/bufrw-1.4.0.tgz", + "integrity": "sha512-sWm8iPbqvL9+5SiYxXH73UOkyEbGQg7kyHQmReF89WJHQJw2eV4P/yZ0E+b71cczJ4pPobVhXxgQcmfSTgGHxQ==", + "dependencies": { + "ansi-color": "^0.2.1", + "error": "^7.0.0", + "hexer": "^1.5.0", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 0.10.x" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.3.tgz", + "integrity": "sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg==", + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001620", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001620.tgz", + "integrity": "sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "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==", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "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, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/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, + "engines": { + "node": ">=10" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "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", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "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==", + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "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==", + "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, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true + }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "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==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compress-commons": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", + "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "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==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "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==", + "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==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "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==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "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==" + }, + "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==", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", + "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + }, + "engines": { + "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, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "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==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "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==" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "optional": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/dedent": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "dev": true, + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "optional": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "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==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "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, + "dependencies": { + "xtend": "^4.0.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "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==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.772", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.772.tgz", + "integrity": "sha512-jFfEbxR/abTTJA3ci+2ok1NTuOBBtB4jH+UT6PUmRN+DY3WSD4FFRsgoVQ+QNIJ0T7wrXwzsWCI2WKC46b++2A==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "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==" + }, + "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==" + }, + "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==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "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==", + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" + }, + "node_modules/error": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", + "integrity": "sha512-UtVv4l5MhijsYUxPJo4390gzfZvAnTHreNnDjnTZaKIiZ/SemXxAhBkYSKtWa5RtBXbLP8tMgn/n0RUa/H7jXw==", + "dependencies": { + "string-template": "~0.2.1", + "xtend": "~4.0.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "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==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "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==", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/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": ">=4" + } + }, + "node_modules/eslint": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.16.0.tgz", + "integrity": "sha512-iVWPS785RuDA4dWuhhgXTNrGxHHK3a8HLSMBgbbU59ruJDubUraXN8N5rn7kb8tG6sjg74eE0RA3YWT51eusEw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.2.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^6.0.0", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.4", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/eslint/node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint/node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/exceljs": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/exceljs/-/exceljs-4.4.0.tgz", + "integrity": "sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg==", + "dependencies": { + "archiver": "^5.0.0", + "dayjs": "^1.8.34", + "fast-csv": "^4.3.1", + "jszip": "^3.10.1", + "readable-stream": "^3.6.0", + "saxes": "^5.0.1", + "tmp": "^0.2.0", + "unzipper": "^0.10.11", + "uuid": "^8.3.0" + }, + "engines": { + "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", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==" + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/fast-csv": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz", + "integrity": "sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==", + "dependencies": { + "@fast-csv/format": "4.3.5", + "@fast-csv/parse": "4.3.6" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "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==" + }, + "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 + }, + "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==" + }, + "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, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, + "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, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "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==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "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==" + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.0.tgz", + "integrity": "sha512-CrWQNaEl1/6WeZoarcM9LHupTo3RpZO2Pdk1vktwzPiQTsJnAKJmm3TACKeG5UZbWDfaH2AbvYxzP96y0MT7fA==", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "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==", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "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", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "deprecated": "This package is no longer supported.", + "dependencies": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/fstream/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fstream/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "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==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", + "deprecated": "This package is no longer supported.", + "optional": true, + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "optional": true + }, + "node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "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==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "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==" + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/helmet": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.1.0.tgz", + "integrity": "sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg==", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/hexer": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/hexer/-/hexer-1.5.0.tgz", + "integrity": "sha512-dyrPC8KzBzUJ19QTIo1gXNqIISRXQ0NwteW6OeQHRN4ZuZeHkdODfj0zHBdOlHbRY8GqbqK57C9oWSvQZizFsg==", + "dependencies": { + "ansi-color": "^0.2.1", + "minimist": "^1.1.0", + "process": "^0.10.0", + "xtend": "^4.0.0" + }, + "bin": { + "hexer": "cli.js" + }, + "engines": { + "node": ">= 0.10.x" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "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==" + }, + "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==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/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==" + }, + "node_modules/http-proxy-middleware": { + "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==", + "dependencies": { + "@types/http-proxy": "^1.17.10", + "debug": "^4.3.4", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.5" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-middleware/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/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==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/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==" + }, + "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, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "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" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "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==", + "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.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/ioredis/node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/ioredis/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "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==" + }, + "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, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "optional": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==" + }, + "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==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz", + "integrity": "sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "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, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", + "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jaeger-client": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/jaeger-client/-/jaeger-client-3.19.0.tgz", + "integrity": "sha512-M0c7cKHmdyEUtjemnJyx/y9uX16XHocL46yQvyqDlPdvAcwPDbHrIbKjQdBqtiE4apQ/9dmr+ZLJYYPGnurgpw==", + "dependencies": { + "node-int64": "^0.4.0", + "opentracing": "^0.14.4", + "thriftrw": "^3.5.0", + "uuid": "^8.3.2", + "xorshift": "^1.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jaeger-client/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-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, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-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, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-config/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-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, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-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, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "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 + }, + "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, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "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==" + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "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 + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "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, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonpath": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz", + "integrity": "sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==", + "dependencies": { + "esprima": "1.2.2", + "static-eval": "2.0.2", + "underscore": "1.12.1" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/kafka-node": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/kafka-node/-/kafka-node-5.0.0.tgz", + "integrity": "sha512-dD2ga5gLcQhsq1yNoQdy1MU4x4z7YnXM5bcG9SdQuiNr5KKuAmXixH1Mggwdah5o7EfholFbcNDPSVA6BIfaug==", + "dependencies": { + "async": "^2.6.2", + "binary": "~0.3.0", + "bl": "^2.2.0", + "buffer-crc32": "~0.2.5", + "buffermaker": "~1.2.0", + "debug": "^2.1.3", + "denque": "^1.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "nested-error-stacks": "^2.0.0", + "optional": "^0.1.3", + "retry": "^0.10.1", + "uuid": "^3.0.0" + }, + "engines": { + "node": ">=8.5.1" + }, + "optionalDependencies": { + "snappy": "^6.0.1" + } + }, + "node_modules/kafka-node/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "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" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "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, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==" + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" + }, + "node_modules/lodash.groupby": { + "version": "4.6.0", + "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", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, + "node_modules/lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==" + }, + "node_modules/lodash.isnil": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", + "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isundefined": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", + "integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==" + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "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==", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/logform/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "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/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/make-dir": { + "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, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/make-fetch-happen": { + "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", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "proc-log": "^4.2.0", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "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, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "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 + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "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==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "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" + } + }, + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-fetch": { + "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", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/morgan/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "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==", + "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==", + "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 + }, + "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==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nested-error-stacks": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz", + "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==" + }, + "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==", + "optional": true, + "dependencies": { + "semver": "^5.4.1" + } + }, + "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==", + "dependencies": { + "clone": "2.x" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/node-gyp": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz", + "integrity": "sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/node-gyp/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "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 + }, + "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==", + "optional": true + }, + "node_modules/nopt": { + "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" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "deprecated": "This package is no longer supported.", + "optional": true, + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "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==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "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==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opentracing": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/opentracing/-/opentracing-0.14.7.tgz", + "integrity": "sha512-vz9iS7MJ5+Bp1URw8Khvdyw1H/hGvzHWlKQ7eRrQojSCDL1/SrWfrY9QebLw97n2deyRtzHRC3MkQfVNUCo91Q==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/optional": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/optional/-/optional-0.1.4.tgz", + "integrity": "sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw==" + }, + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "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.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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==" + }, + "node_modules/pg": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.12.0.tgz", + "integrity": "sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ==", + "dev": true, + "dependencies": { + "pg-connection-string": "^2.6.4", + "pg-pool": "^3.6.2", + "pg-protocol": "^1.6.1", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "dev": true, + "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 + }, + "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, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-numeric": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", + "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg-pool": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.2.tgz", + "integrity": "sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==", + "dev": true, + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.1.tgz", + "integrity": "sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==", + "dev": true + }, + "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, + "dependencies": { + "pg-int8": "1.0.1", + "pg-numeric": "1.0.2", + "postgres-array": "~3.0.1", + "postgres-bytea": "~3.0.0", + "postgres-date": "~2.1.0", + "postgres-interval": "^3.0.0", + "postgres-range": "^1.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pg/node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dev": true, + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg/node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg/node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pg/node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pg/node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dev": true, + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dev": true, + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "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==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postgres-array": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", + "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/postgres-bytea": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", + "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", + "dev": true, + "dependencies": { + "obuf": "~1.1.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postgres-date": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", + "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/postgres-interval": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", + "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/postgres-range": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz", + "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==", + "dev": true + }, + "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==", + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.7.0", + "noop-logger": "^0.1.1", + "npmlog": "^4.0.1", + "os-homedir": "^1.0.1", + "pump": "^2.0.1", + "rc": "^1.2.7", + "simple-get": "^2.7.0", + "tar-fs": "^1.13.0", + "tunnel-agent": "^0.6.0", + "which-pm-runs": "^1.0.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/prelude-ls": { + "version": "1.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/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/process": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/process/-/process-0.10.1.tgz", + "integrity": "sha512-dyIett8dgGIZ/TXKUzeYExt7WA6ldDzys9vTDU/cCA9L17Ypme+KzS+NjQCjpn9xsvi/shbMC+yP/BcFMBz0NA==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "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, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/prom-client": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-14.2.0.tgz", + "integrity": "sha512-sF308EhTenb/pDRPakm+WgiN+VdM/T1RaHj1x+MvAuT8UiQP8JmOEbxVqtkbfR4LrvOg5n7ic01kRBDGXjYikA==", + "dev": true, + "dependencies": { + "tdigest": "^0.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/promise-retry/node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/property-expr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==" + }, + "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==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "optional": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "optional": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/react-is": { + "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==", + "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/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "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, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha512-ZXUSQYTHdl3uS7IuCehYfMzKyIDBNoAuUblvy5oGO5UJSUTmStUUVPXbA9Qxd173Bgre53yCQczQuHgRWAdvJQ==", + "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==", + "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/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "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==", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "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" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "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==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "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==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "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==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "devOptional": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "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==", + "optional": true, + "dependencies": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/snappy": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/snappy/-/snappy-6.3.5.tgz", + "integrity": "sha512-lonrUtdp1b1uDn1dbwgQbBsb5BbaiLeKq+AGwOk2No+en+VvJThwmtztwulEQsLinRF681pBqib0NUZaizKLIA==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "bindings": "^1.3.1", + "nan": "^2.14.1", + "prebuild-install": "5.3.0" + } + }, + "node_modules/socks": { + "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" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", + "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/socks-proxy-agent/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/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==" + }, + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "engines": { + "node": ">= 10.x" + } + }, + "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==" + }, + "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==", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ssri": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", + "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "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==", + "dependencies": { + "escodegen": "^1.8.1" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "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", + "integrity": "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw==" + }, + "node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "optional": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "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==", + "engines": { + "node": ">=8" + } + }, + "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": ">=8" + } + }, + "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==", + "optional": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "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" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/table": { + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", + "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "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==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-fs": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", + "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", + "optional": true, + "dependencies": { + "chownr": "^1.0.1", + "mkdirp": "^0.5.1", + "pump": "^1.0.0", + "tar-stream": "^1.1.2" + } + }, + "node_modules/tar-fs/node_modules/pump": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", + "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", + "optional": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "optional": true, + "dependencies": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/tar-stream/node_modules/bl": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", + "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", + "optional": true, + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/tar/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tdigest": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", + "integrity": "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==", + "dev": true, + "dependencies": { + "bintrees": "1.0.2" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "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 + }, + "node_modules/thriftrw": { + "version": "3.11.4", + "resolved": "https://registry.npmjs.org/thriftrw/-/thriftrw-3.11.4.tgz", + "integrity": "sha512-UcuBd3eanB3T10nXWRRMwfwoaC6VMk7qe3/5YIWP2Jtw+EbHqJ0p1/K3x8ixiR5dozKSSfcg1W+0e33G1Di3XA==", + "dependencies": { + "bufrw": "^1.2.1", + "error": "7.0.2", + "long": "^2.4.0" + }, + "bin": { + "thrift2json": "thrift2json.js" + }, + "engines": { + "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==" + }, + "node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "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==", + "optional": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==" + }, + "node_modules/traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", + "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, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node-dev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz", + "integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.1", + "dynamic-dedupe": "^0.3.0", + "minimist": "^1.2.6", + "mkdirp": "^1.0.4", + "resolve": "^1.0.0", + "rimraf": "^2.6.1", + "source-map-support": "^0.5.12", + "tree-kill": "^1.2.2", + "ts-node": "^10.4.0", + "tsconfig": "^7.0.0" + }, + "bin": { + "ts-node-dev": "lib/bin.js", + "tsnd": "lib/bin.js" + }, + "engines": { + "node": ">=0.8.0" + }, + "peerDependencies": { + "node-notifier": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/ts-node-dev/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ts-node-dev/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-node-dev/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/ts-node/node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/tsconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", + "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", + "dev": true, + "dependencies": { + "@types/strip-bom": "^3.0.0", + "@types/strip-json-comments": "0.0.30", + "strip-bom": "^3.0.0", + "strip-json-comments": "^2.0.0" + } + }, + "node_modules/tsconfig/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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==", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "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==", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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==", + "engines": { + "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==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/underscore": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" + }, + "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==" + }, + "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==", + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unzipper": { + "version": "0.10.14", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", + "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==", + "dependencies": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", + "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "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==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", + "dev": true + }, + "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 + }, + "node_modules/v8-to-istanbul": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", + "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "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==", + "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==", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/winston": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.12.0.tgz", + "integrity": "sha512-OwbxKaOlESDi01mC9rkM0dQqQt2I8DAUMRLZ/HpbwvDXm85IryEHgoogy5fziQy38PntgZsLlhAYHz//UPHZ5w==", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.7.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", + "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", + "dependencies": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "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==" + }, + "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==", + "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==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "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/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "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": ">=8" + }, + "funding": { + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-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": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "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==" + }, + "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, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/xlsx-populate": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/xlsx-populate/-/xlsx-populate-1.21.0.tgz", + "integrity": "sha512-8v2Gm8BehXo6LU7KT802QoXTPkYY1SKk5V8g/UuYZnNB3JzXqud/P99Pxr2yXeKyt+sKlCatmidz6jQNie1hRw==", + "dependencies": { + "cfb": "^1.1.3", + "jszip": "^3.2.2", + "lodash": "^4.17.15", + "sax": "^1.2.4" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, + "node_modules/xorshift": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/xorshift/-/xorshift-1.2.0.tgz", + "integrity": "sha512-iYgNnGyeeJ4t6U11NpA/QiKy+PXn5Aa3Azg5qkwIFz1tBLllQrjjsk9yzD7IAK0naNU4JxdeDgqW9ov4u/hc4g==" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "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, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "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, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yup": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/yup/-/yup-1.4.0.tgz", + "integrity": "sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg==", + "dependencies": { + "property-expr": "^2.0.5", + "tiny-case": "^1.0.3", + "toposort": "^2.0.2", + "type-fest": "^2.19.0" + } + }, + "node_modules/zip-stream": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", + "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", + "dependencies": { + "archiver-utils": "^3.0.4", + "compress-commons": "^4.1.2", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/archiver-utils": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", + "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", + "dependencies": { + "glob": "^7.2.3", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/zip-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "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 new file mode 100644 index 00000000000..31dd40bc152 --- /dev/null +++ b/health-services/project-factory/package.json @@ -0,0 +1,70 @@ +{ + "name": "project-factory", + "version": "0.2.0", + "main": "src/server/index.ts", + "author": "Jagankumar ", + "description": "Backend For Frontend service", + "license": "MIT", + "private": true, + "scripts": { + "build": "yarn run build-ts", + "build-ts": "tsc", + "clean": "rm -rf ./dist", + "serve": "node dist/index.js", + "start": "yarn run dev", + "test": "jest", + "dev": "ts-node-dev --respawn src/server/index.ts", + "prod": "yarn build && yarn serve", + "watch-ts": "tsc --watch" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/egovernments/DIGIT-Frontend.git" + }, + "dependencies": { + "ajv-errors": "^3.0.0", + "axios": "1.6.8", + "body-parser": "^1.20.2", + "compression": "1.7.4", + "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", + "lodash": "4.17.21", + "morgan": "1.10.0", + "node-cache": "5.1.2", + "node-gyp": "10.0.1", + "opentracing": "^0.14.7", + "uuid": "9.0.1", + "winston": "3.12.0", + "xlsx": "0.18.5", + "xlsx-populate": "1.21.0", + "yup": "1.4.0" + }, + "devDependencies": { + "@types/compression": "1.7.5", + "@types/express": "4.17.21", + "@types/hash-sum": "1.0.2", + "@types/helmet": "0.0.47", + "@types/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", + "@types/uuid": "9.0.8", + "@types/xlsx": "0.0.36", + "ajv": "^8.16.0", + "eslint": "7.16.0", + "jest": "29.7.0", + "pg": "8.12.0", + "ts-node-dev": "2.0.0", + "typescript": "5.4.2" + } +} diff --git a/health-services/project-factory/postman_collection.json b/health-services/project-factory/postman_collection.json new file mode 100644 index 00000000000..d99524df3c1 --- /dev/null +++ b/health-services/project-factory/postman_collection.json @@ -0,0 +1,1088 @@ +{ + "info": { + "_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": "28207698" + }, + "item": [ + { + "name": "campain-manage-create Copy", + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-dev.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + }, + { + "key": "origin", + "value": "https://unified-dev.digit.org" + }, + { + "key": "referer", + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n // 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": "http://localhost:8080/project-factory/v1/project-type/createCampaign", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "project-factory", + "v1", + "project-type", + "createCampaign" + ] + } + }, + "response": [] + }, + { + "name": "mdms bulk search Copy", + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-dev.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + }, + { + "key": "origin", + "value": "https://unified-dev.digit.org" + }, + { + "key": "referer", + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{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": "http://localhost:8080/mdms-bff/v1/mdmsbulk/search?tenantId=mz&schemaName=Dummy.dummy", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "mdms-bff", + "v1", + "mdmsbulk", + "search" + ], + "query": [ + { + "key": "tenantId", + "value": "mz" + }, + { + "key": "schemaName", + "value": "Dummy.dummy" + } + ] + } + }, + "response": [] + }, + { + "name": "campaign-generate Copy", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "content-type": true + } + }, + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-uat.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1ho6v1de2.1ho6v2ouk.ot.21.qu; _ga_H9YC8FEN6F=GS1.1.1709630860.87.1.1709630957.60.0.0; PGADMIN_LANGUAGE=en" + }, + { + "key": "origin", + "value": "https://unified-uat.digit.org" + }, + { + "key": "referer", + "value": "https://unified-uat.digit.org/workbench-ui/employee/campaign/setup-campaign?id=22f77798-3645-44b3-98ee-cc5c0ff2888c&draft=true&fetchBoundary=true&key=8&preview=false&skip=false" + }, + { + "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 \"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": "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": [ + "localhost" + ], + "port": "8080", + "path": [ + "project-factory", + "v1", + "data", + "_generate" + ], + "query": [ + { + "key": "tenantId", + "value": "mz" + }, + { + "key": "type", + "value": "userWithBoundary" + }, + { + "key": "forceUpdate", + "value": "true" + }, + { + "key": "hierarchyType", + "value": "ADMIN" + }, + { + "key": "campaignId", + "value": "3b331cd6-c0e9-4fd4-9d15-9212ba51706c" + } + ] + } + }, + "response": [] + }, + { + "name": "download-generated Copy", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "content-type": true + } + }, + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-dev.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json", + "disabled": true + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + }, + { + "key": "origin", + "value": "https://unified-dev.digit.org" + }, + { + "key": "referer", + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"b902a184-4582-41f8-8144-99930548631d\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1716457221446|en_MZ\",\n \"plainAccessRequest\": {}\n}\n}" + }, + "url": { + "raw": "https://unified-uat.digit.org/project-factory/v1/data/_download?tenantId=mz&hierarchyType=ADMIN&id=9a857a1b-ea6f-49ac-aaca-354de76f7cf3&type=boundary", + "protocol": "https", + "host": [ + "unified-uat", + "digit", + "org" + ], + "path": [ + "project-factory", + "v1", + "data", + "_download" + ], + "query": [ + { + "key": "tenantId", + "value": "mz" + }, + { + "key": "hierarchyType", + "value": "ADMIN" + }, + { + "key": "forecUpdate", + "value": "true", + "disabled": true + }, + { + "key": "id", + "value": "9a857a1b-ea6f-49ac-aaca-354de76f7cf3" + }, + { + "key": "type", + "value": "boundary" + } + ] + } + }, + "response": [] + }, + { + "name": "project-factory/v1/data/_create Copy", + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-uat.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1ho6v1de2.1ho6v2ouk.ot.21.qu; _ga_H9YC8FEN6F=GS1.1.1709630860.87.1.1709630957.60.0.0; PGADMIN_LANGUAGE=en" + }, + { + "key": "origin", + "value": "https://unified-uat.digit.org" + }, + { + "key": "referer", + "value": "https://unified-uat.digit.org/workbench-ui/employee/campaign/setup-campaign?id=3a567d66-9de5-4812-9441-240ae6ccb674&draft=true&fetchBoundary=true&key=9&preview=false" + }, + { + "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 \"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", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "project-factory", + "v1", + "data", + "_create" + ] + } + }, + "response": [] + }, + { + "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": [ + { + "key": "authority", + "value": "unified-dev.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + }, + { + "key": "origin", + "value": "https://unified-dev.digit.org" + }, + { + "key": "referer", + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"49109c15-ca23-4399-931c-3df81c114302\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1713364121714|en_MZ\",\n \"plainAccessRequest\": {}\n},\n \"SearchCriteria\": {\n \"id\": [\n \"636faa32-661c-42bb-b955-837111f63773\"\n ],\n \"tenantId\": \"mz\",\n \"type\": \"facility\",\n \"status\": \"completed\"\n }\n}" + }, + "url": { + "raw": "http://localhost:8080/project-factory/v1/data/_search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "project-factory", + "v1", + "data", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "", + "disabled": true + } + ] + } + }, + "response": [ + { + "name": "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": "/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 + } + }, + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-dev.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + }, + { + "key": "origin", + "value": "https://unified-dev.digit.org" + }, + { + "key": "referer", + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{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": "https://unified-dev.digit.org/project-factory/v1/project-type/create", + "protocol": "https", + "host": [ + "unified-dev", + "digit", + "org" + ], + "path": [ + "project-factory", + "v1", + "project-type", + "create" + ] + } + }, + "response": [] + }, + { + "name": "/project-factory/v1/project-type/update Copy", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "content-type": true + } + }, + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-dev.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + }, + { + "key": "origin", + "value": "https://unified-dev.digit.org" + }, + { + "key": "referer", + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"44cb5589-8dc2-4182-b5a4-afdb692ce831\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1713364121714|en_MZ\",\n \"plainAccessRequest\": {}\n },\n \"CampaignDetails\": {\n \"id\": \"{{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-dev.digit.org/project-factory/v1/project-type/update", + "protocol": "https", + "host": [ + "unified-dev", + "digit", + "org" + ], + "path": [ + "project-factory", + "v1", + "project-type", + "update" + ] + } + }, + "response": [] + }, + { + "name": "getProcessTracks Copy", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "content-type": true + } + }, + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-dev.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + }, + { + "key": "origin", + "value": "https://unified-dev.digit.org" + }, + { + "key": "referer", + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{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": "https://unified-dev.digit.org/project-factory/v1/project-type/getProcessTrack?campaignId=eeded5f1-e779-454f-9cc7-2b20ba4839e0", + "protocol": "https", + "host": [ + "unified-dev", + "digit", + "org" + ], + "path": [ + "project-factory", + "v1", + "project-type", + "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 new file mode 100644 index 00000000000..c063f1e653d --- /dev/null +++ b/health-services/project-factory/src/server/api/campaignApis.ts @@ -0,0 +1,1067 @@ +import config from "../config"; +import { v4 as uuidv4 } from 'uuid'; +import { httpRequest } from "../utils/request"; +import { getFormattedStringForDebug, logger } from "../utils/logger"; +import createAndSearch from '../config/createAndSearch'; +import { getDataFromSheet, generateActivityMessage, throwError, translateSchema, replicateRequest, appendProjectTypeToCapacity } from "../utils/genericUtils"; +import { immediateValidationForTargetSheet, validateSheetData, validateTargetSheetData } from '../validators/campaignValidators'; +import { callMdmsTypeSchema, getCampaignNumber } from "./genericApis"; +import { boundaryBulkUpload, convertToTypeData, generateHierarchy, generateProcessedFileAndPersist, getBoundaryOnWhichWeSplit, getLocalizedName, reorderBoundariesOfDataAndValidate, checkIfSourceIsMicroplan } 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 } from "../config/constants"; +import { persistTrack } from "../utils/processTrackUtils"; + + + +/** + * Enriches the campaign data with unique IDs and generates campaign numbers. + * @param requestBody The request body containing the campaign data. + */ +async function enrichCampaign(requestBody: any) { + // Enrich campaign data with unique IDs and generate campaign numbers + if (requestBody?.Campaign) { + requestBody.Campaign.id = uuidv4(); + requestBody.Campaign.campaignNo = await getCampaignNumber(requestBody, config.values.idgen.format, config.values.idgen.idName, requestBody?.Campaign?.tenantId); + for (const campaignDetails of requestBody?.Campaign?.CampaignDetails) { + campaignDetails.id = uuidv4(); + } + } +} + +async function getAllFacilitiesInLoop(searchedFacilities: any[], facilitySearchParams: any, facilitySearchBody: any) { + const response = await httpRequest(config.host.facilityHost + config.paths.facilitySearch, facilitySearchBody, facilitySearchParams); + + if (Array.isArray(response?.Facilities)) { + searchedFacilities.push(...response?.Facilities); + return response.Facilities.length >= 50; // Return true if there are more facilities to fetch, false otherwise + } else { + throwError("FACILITY", 500, "FACILITY_SEARCH_FAILED"); + return false; + } +} + +/** + * Retrieves all facilities for a given tenant ID. + * @param tenantId The ID of the tenant. + * @param requestBody The request body containing additional parameters. + * @returns An array of facilities. + */ +async function getAllFacilities(tenantId: string, requestBody: any) { + // Retrieve all facilities for the given tenant ID + const facilitySearchBody = { + RequestInfo: requestBody?.RequestInfo, + Facility: { isPermanent: true } + }; + + const facilitySearchParams = { + limit: 50, + offset: 0, + tenantId: tenantId?.split('.')?.[0] + }; + + const searchedFacilities: any[] = []; + let searchAgain = true; + + while (searchAgain) { + searchAgain = await getAllFacilitiesInLoop(searchedFacilities, facilitySearchParams, facilitySearchBody); + facilitySearchParams.offset += 50; + } + + return searchedFacilities; +} + +/** + * Retrieves facilities by their IDs. + * @param tenantId The ID of the tenant. + * @param ids An array of facility IDs. + * @param requestBody The request body containing additional parameters. + * @returns An array of facilities. + */ +async function getFacilitiesViaIds(tenantId: string, ids: any[], requestBody: any) { + // Retrieve facilities by their IDs + const facilitySearchBody: any = { + RequestInfo: requestBody?.RequestInfo, + Facility: {} + }; + + const facilitySearchParams = { + limit: 50, + offset: 0, + tenantId: tenantId?.split('.')?.[0] + }; + + const searchedFacilities: any[] = []; + + // Split ids into chunks of 50 + for (let i = 0; i < ids.length; i += 50) { + const chunkIds = ids.slice(i, i + 50); + facilitySearchBody.Facility.id = chunkIds; + await getAllFacilitiesInLoop(searchedFacilities, facilitySearchParams, facilitySearchBody); + } + + return searchedFacilities; +} + +/** + * Retrieves parameters based on elements. + * @param elements An array of elements. + * @param request The HTTP request object. + * @returns Parameters extracted from elements. + */ +function getParamsViaElements(elements: any, request: any) { + // Extract parameters based on elements + var params: any = {}; + if (!elements) { + return params; + } + for (const element of elements) { + if (element?.isInParams) { + if (element?.value) { + _.set(params, element?.keyPath, element?.value); + } + else if (element?.getValueViaPath) { + _.set(params, element?.keyPath, _.get(request.body, element?.getValueViaPath)) + } + } + } + return params +} + +/** + * Changes request body based on elements. + * @param elements An array of elements. + * @param requestBody The request body to be modified. + */ +function changeBodyViaElements(elements: any, requestBody: any) { + // Modify request body based on elements + if (!elements) { + return; + } + for (const element of elements) { + if (element?.isInBody) { + if (element?.value) { + _.set(requestBody, element?.keyPath, element?.value); + } + else if (element?.getValueViaPath) { + _.set(requestBody, element?.keyPath, _.get(requestBody, element?.getValueViaPath)) + } + else { + _.set(requestBody, element?.keyPath, {}) + } + } + } +} + +// function changeBodyViaSearchFromSheet(elements: any, request: any, dataFromSheet: any) { +// if (!elements) { +// return; +// } +// for (const element of elements) { +// const arrayToSearch = [] +// for (const data of dataFromSheet) { +// if (data[element.sheetColumnName]) { +// arrayToSearch.push(data[element.sheetColumnName]); +// } +// } +// _.set(request.body, element?.searchPath, arrayToSearch); +// } +// } + +function updateErrorsForUser(newCreatedData: any[], newSearchedData: any[], errors: any[], createAndSearchConfig: any, userNameAndPassword: any[]) { + newCreatedData.forEach((createdElement: any) => { + let foundMatch = false; + for (const searchedElement of newSearchedData) { + if (searchedElement?.code === createdElement?.code) { + foundMatch = true; + newSearchedData.splice(newSearchedData.indexOf(searchedElement), 1); + errors.push({ status: "CREATED", rowNumber: createdElement["!row#number!"], isUniqueIdentifier: true, uniqueIdentifier: _.get(searchedElement, createAndSearchConfig.uniqueIdentifier, ""), errorDetails: "" }) + userNameAndPassword.push({ + userName: searchedElement?.user?.userName, + password: createdElement?.user?.password, + rowNumber: createdElement["!row#number!"] + }) + break; + } + } + if (!foundMatch) { + errors.push({ status: "NOT_CREATED", rowNumber: createdElement["!row#number!"], errorDetails: `Can't confirm creation of this data` }) + logger.info("Can't confirm creation of this data of row number : " + createdElement["!row#number!"]); + } + }); +} + +function updateErrors(newCreatedData: any[], newSearchedData: any[], errors: any[], createAndSearchConfig: any) { + newCreatedData.forEach((createdElement: any) => { + let foundMatch = false; + for (const searchedElement of newSearchedData) { + let match = true; + for (const key in createdElement) { + if (createdElement[key] !== searchedElement[key] && key != '!row#number!') { + match = false; + break; + } + } + if (match) { + foundMatch = true; + newSearchedData.splice(newSearchedData.indexOf(searchedElement), 1); + errors.push({ status: "CREATED", rowNumber: createdElement["!row#number!"], isUniqueIdentifier: true, uniqueIdentifier: _.get(searchedElement, createAndSearchConfig.uniqueIdentifier, ""), errorDetails: "" }) + break; + } + } + if (!foundMatch) { + errors.push({ status: "NOT_CREATED", rowNumber: createdElement["!row#number!"], errorDetails: `Can't confirm creation of this data` }) + logger.info("Can't confirm creation of this data of row number : " + createdElement["!row#number!"]); + } + }); +} + + +function matchCreatedAndSearchedData(createdData: any[], searchedData: any[], request: any, createAndSearchConfig: any, activities: any) { + const newCreatedData = JSON.parse(JSON.stringify(createdData)); + const newSearchedData = JSON.parse(JSON.stringify(searchedData)); + const uid = createAndSearchConfig.uniqueIdentifier; + newCreatedData.forEach((element: any) => { + delete element[uid]; + }) + var errors: any[] = [] + if (request?.body?.ResourceDetails?.type != "user") { + if (request?.body?.ResourceDetails?.type == "facility") { + newCreatedData?.forEach((element: any) => { + delete element.address + }) + } + updateErrors(newCreatedData, newSearchedData, errors, createAndSearchConfig); + } + else { + var userNameAndPassword: any = [] + updateErrorsForUser(newCreatedData, newSearchedData, errors, createAndSearchConfig, userNameAndPassword); + request.body.userNameAndPassword = userNameAndPassword + } + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; + request.body.Activities = activities +} + +async function getUuidsError(request: any, response: any, mobileNumberRowNumberMapping: any) { + var errors: any[] = [] + var count = 0; + 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` }) + 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` }) + count++; + } + else if (!user?.userDetails?.password) { + logger.info(`User with mobileNumber ${user?.mobileNumber} doesn't have password`) + errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have password` }) + count++; + } + else if (!user?.userUuid) { + logger.info(`User with mobileNumber ${user?.mobileNumber} doesn't have userServiceUuid`) + errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have userServiceUuid` }) + count++; + } + else { + request.body.mobileNumberUuidsMapping[user?.mobileNumber] = { userUuid: user?.id, code: user?.userDetails?.username, rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], password: user?.userDetails?.password, userServiceUuid: user?.userUuid } + } + } + if (count > 0) { + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; + } +} + +const createBatchRequest = async (request: any, batch: any[], mobileNumberRowNumberMapping: any) => { + const searchBody = { + RequestInfo: request?.body?.RequestInfo, + Individual: { + mobileNumber: batch + } + }; + const params = { + limit: 55, + offset: 0, + tenantId: request?.body?.ResourceDetails?.tenantId, + 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); + + if (!response) { + throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "Error occurred during user search while validating mobile number."); + } + if (config.values.notCreateUserIfAlreadyThere) { + await getUuidsError(request, response, mobileNumberRowNumberMapping); + } + + if (response?.Individual?.length > 0) { + return response.Individual.map((item: any) => item?.mobileNumber); + } + return []; +}; + +async function getUserWithMobileNumbers(request: any, mobileNumbers: any[], mobileNumberRowNumberMapping: any) { + logger.info("mobileNumbers to search: " + JSON.stringify(mobileNumbers)); + const BATCH_SIZE = 50; + let allResults: any[] = []; + + // Create an array of batch promises + 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)); + } + + // Wait for all batch requests to complete + const batchResults = await Promise.all(batchPromises); + + // Aggregate all results + for (const result of batchResults) { + allResults = allResults.concat(result); + } + // Convert the results array to a Set to eliminate duplicates + const resultSet = new Set(allResults); + logger.info(`Already Existing mobile numbers : ${JSON.stringify(resultSet)}`); + 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 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); + 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` }) + count++; + } + } + if (count) { + request.body.ResourceDetails.status = "invalid" + } + logger.info("Invalid resources count : " + count); + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; +} +function matchViaUserIdAndCreationTime(createdData: any[], searchedData: any[], request: any, creationTime: any, createAndSearchConfig: any, activities: any) { + var matchingSearchData = []; + const userUuid = request?.body?.RequestInfo?.userInfo?.uuid + var count = 0; + if (request?.body?.ResourceDetails?.type != "user") { + for (const data of searchedData) { + if (data?.auditDetails?.createdBy == userUuid && data?.auditDetails?.createdTime >= creationTime) { + matchingSearchData.push(data); + count++; + } + } + } + else { + count = searchedData.length; + matchingSearchData = searchedData; + } + if (count < createdData.length) { + request.body.ResourceDetails.status = "PERSISTER_ERROR" + } + matchCreatedAndSearchedData(createdData, matchingSearchData, request, createAndSearchConfig, activities); + logger.info("New created resources count : " + count); +} + +async function processSearch(createAndSearchConfig: any, request: any, params: any) { + setSearchLimits(createAndSearchConfig, request, params); + const arraysToMatch = await performSearch(createAndSearchConfig, request, params); + return arraysToMatch; +} + +function setSearchLimits(createAndSearchConfig: any, request: any, params: any) { + setLimitOrOffset(createAndSearchConfig?.searchDetails?.searchLimit, params, request.body); + setLimitOrOffset(createAndSearchConfig?.searchDetails?.searchOffset, params, request.body); +} + +function setLimitOrOffset(limitOrOffsetConfig: any, params: any, requestBody: any) { + if (limitOrOffsetConfig) { + if (limitOrOffsetConfig?.isInParams) { + _.set(params, limitOrOffsetConfig?.keyPath, parseInt(limitOrOffsetConfig?.value)); + } + if (limitOrOffsetConfig?.isInBody) { + _.set(requestBody, limitOrOffsetConfig?.keyPath, parseInt(limitOrOffsetConfig?.value)); + } + } +} + +async function performSearch(createAndSearchConfig: any, request: any, params: any) { + const arraysToMatch: any[] = []; + let searchAgain = true; + while (searchAgain) { + const searcRequestBody = { + RequestInfo: request?.body?.RequestInfo + } + changeBodyViaElements(createAndSearchConfig?.searchDetails?.searchElements, searcRequestBody) + const response = await httpRequest(createAndSearchConfig?.searchDetails?.url, searcRequestBody, params); + const resultArray = _.get(response, createAndSearchConfig?.searchDetails?.searchPath); + if (resultArray && Array.isArray(resultArray)) { + arraysToMatch.push(...resultArray); + if (resultArray.length < parseInt(createAndSearchConfig?.searchDetails?.searchLimit?.value)) { + searchAgain = false; + } + } else { + searchAgain = false; + } + updateOffset(createAndSearchConfig, params, request.body); + } + return arraysToMatch; +} + +function updateOffset(createAndSearchConfig: any, params: any, requestBody: any) { + const offsetConfig = createAndSearchConfig?.searchDetails?.searchOffset + const limit = createAndSearchConfig?.searchDetails?.searchLimit?.value + if (offsetConfig) { + if (offsetConfig?.isInParams) { + _.set(params, offsetConfig?.keyPath, parseInt(_.get(params, offsetConfig?.keyPath) + parseInt(limit))); + } + if (offsetConfig?.isInBody) { + _.set(requestBody, offsetConfig?.keyPath, parseInt(_.get(requestBody, offsetConfig?.keyPath) + parseInt(limit))); + } + } +} + + +async function processSearchAndValidation(request: any, createAndSearchConfig: any, dataFromSheet: any[]) { + // if (request?.body?.dataToSearch?.length > 0) { + // const params: any = getParamsViaElements(createAndSearchConfig?.searchDetails?.searchElements, request); + // changeBodyViaElements(createAndSearchConfig?.searchDetails?.searchElements, request) + // changeBodyViaSearchFromSheet(createAndSearchConfig?.requiresToSearchFromSheet, request, dataFromSheet) + // const arraysToMatch = await processSearch(createAndSearchConfig, request, params) + // matchData(request, request.body.dataToSearch, arraysToMatch, createAndSearchConfig) + // } + if (request?.body?.ResourceDetails?.type == "user") { + await enrichEmployees(request?.body?.dataToCreate, request) + await matchUserValidation(request.body.dataToCreate, request) + } +} + +async function getEmployeesBasedOnUuids(dataToCreate: any[], request: any) { + const searchBody = { + 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)); + 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 params = { + tenantId: tenantId, + uuids: uuids, + limit: 51, + offset: 0 + }; + + try { + const response = await httpRequest(searchUrl, searchBody, params, undefined, undefined, undefined, undefined, true); + if (response && response.Employees) { + employeesSearched = employeesSearched.concat(response.Employees); + } else { + throw new Error("Unable to fetch employees based on UUIDs"); + } + } catch (error: any) { + console.log(error); + 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) { + // 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) + } +} + +async function processValidateAfterSchema(dataFromSheet: any, request: any, createAndSearchConfig: any, localizationMap?: { [key: string]: string }) { + try { + const typeData = await convertToTypeData(request, dataFromSheet, createAndSearchConfig, request.body, localizationMap) + request.body.dataToSearch = typeData.searchData; + request.body.dataToCreate = typeData.createData; + await processSearchAndValidation(request, createAndSearchConfig, dataFromSheet) + await reorderBoundariesOfDataAndValidate(request, localizationMap) + await generateProcessedFileAndPersist(request, localizationMap); + } catch (error) { + console.log(error) + await handleResouceDetailsError(request, error); + } +} + +async function processValidate(request: any, localizationMap?: { [key: string]: string }) { + const type: string = request.body.ResourceDetails.type; + const tenantId = request.body.ResourceDetails.tenantId; + const createAndSearchConfig = createAndSearch[type] + const dataFromSheet = await getDataFromSheet(request, request?.body?.ResourceDetails?.fileStoreId, request?.body?.ResourceDetails?.tenantId, createAndSearchConfig, null, localizationMap) + if (type == 'boundaryWithTarget') { + let differentTabsBasedOnLevel = await getBoundaryOnWhichWeSplit(request); + differentTabsBasedOnLevel = getLocalizedName(`${request?.body?.ResourceDetails?.hierarchyType}_${differentTabsBasedOnLevel}`.toUpperCase(), localizationMap); + logger.info("target sheet format validation started"); + 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 translatedSchema = await translateSchema(schema, localizationMap); + await validateSheetData(dataFromSheet, request, translatedSchema, createAndSearchConfig?.boundaryValidation, localizationMap) + processValidateAfterSchema(dataFromSheet, request, createAndSearchConfig, localizationMap) + } +} + +function convertUserRoles(employees: any[], request: any) { + for (const employee of employees) { + if (employee?.user?.roles) { + var newRoles: any[] = [] + const rolesArray = employee.user.roles.split(',').map((role: any) => role.trim()); + for (const role of rolesArray) { + const code = role.toUpperCase().split(' ').join('_') + newRoles.push({ name: role, code: code, tenantId: request?.body?.ResourceDetails?.tenantId }) + } + employee.user.roles = newRoles + } + } +} + +function generateHash(input: string): string { + const prime = 31; // Prime number + let hash = 0; + for (let i = 0; i < input.length; i++) { + hash = (hash * prime + input.charCodeAt(i)) % 100000; // Limit hash to 5 digits + } + return hash.toString().padStart(6, '0'); +} + +function generateUserPassword() { + // Function to generate a random lowercase letter + function getRandomLowercaseLetter() { + const letters = 'abcdefghijklmnopqrstuvwxyz'; + return letters.charAt(Math.floor(Math.random() * letters.length)); + } + + // Function to generate a random uppercase letter + function getRandomUppercaseLetter() { + const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + return letters.charAt(Math.floor(Math.random() * letters.length)); + } + + // Generate a random 4-letter sequence where the second letter is uppercase + function generate4LetterSequence() { + const firstLetter = getRandomLowercaseLetter(); + const secondLetter = getRandomUppercaseLetter(); + const thirdLetter = getRandomLowercaseLetter(); + const fourthLetter = getRandomLowercaseLetter(); + return firstLetter + secondLetter + thirdLetter + fourthLetter; + } + + // Generate a random 3-digit number + function getRandom3DigitNumber() { + return Math.floor(100 + Math.random() * 900); // Ensures the number is 3 digits + } + + // Combine parts to form the password + const firstSequence = generate4LetterSequence(); + const randomNumber = getRandom3DigitNumber(); + + 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 = [ + { + tenantId: request?.body?.ResourceDetails?.tenantId, + boundaryType: config.values.userMainBoundaryType, + boundary: config.values.userMainBoundary, + hierarchy: request?.body?.ResourceDetails?.hierarchyType, + roles: employee?.user?.roles + } + ] +} + +async function enrichEmployees(employees: any[], request: any) { + convertUserRoles(employees, request) + for (const employee of employees) { + enrichUserNameAndPassword(employees) + await enrichJurisdictions(employee, request) + if (employee?.user) { + employee.user.tenantId = request?.body?.ResourceDetails?.tenantId + employee.user.dob = 0 + } + } +} + +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 + const employeeMap = createdEmployees.reduce((map: any, employee: any) => { + map[employee.code] = employee.uuid; + return map; + }, {}); + for (const employee of dataToCreate) { + if (!employee?.uuid && employeeMap[employee?.code]) { + employee.uuid = employeeMap[employee?.code]; + } + } +} + +async function handeFacilityProcess(request: any, createAndSearchConfig: any, params: any, activities: any[], newRequestBody: any) { + for (const facility of newRequestBody.Facilities) { + 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}`); + activities.push(activity); +} + + +async function handleUserProcess(request: any, createAndSearchConfig: any, params: any, dataToCreate: any[], activities: any[], newRequestBody: any) { + if (config.values.notCreateUserIfAlreadyThere) { + 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) + } + } + } + newRequestBody.Employees = Employees + } + if (newRequestBody.Employees.length > 0) { + var responsePayload = await httpRequest(createAndSearchConfig?.createBulkDetails?.url, newRequestBody, params, "post", undefined, undefined, true, true); + 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."); + } + 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) { + 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 = 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 }) { + logger.info(type + " create data "); + if (createAndSearchConfig?.createBulkDetails?.limit) { + const limit = createAndSearchConfig?.createBulkDetails?.limit; + const dataToCreate = request?.body?.dataToCreate; + const chunks = Math.ceil(dataToCreate.length / limit); // Calculate number of chunks + var creationTime = Date.now(); + var activities: any[] = []; + for (let i = 0; i < chunks; i++) { + const start = i * limit; + const end = (i + 1) * limit; + const chunkData = dataToCreate.slice(start, end); // Get a chunk of data + const newRequestBody: any = { + RequestInfo: request?.body?.RequestInfo, + } + _.set(newRequestBody, createAndSearchConfig?.createBulkDetails?.createPath, chunkData); + creationTime = Date.now(); + if (type == "facility" || type == "facilityMicroplan") { + await handeFacilityProcess(request, createAndSearchConfig, params, activities, newRequestBody); + } + else if (type == "user") { + await handleUserProcess(request, createAndSearchConfig, params, chunkData, activities, newRequestBody); + } + } + await enrichAlreadyExsistingUser(request); + logger.info(`Waiting for 10 seconds`); + await new Promise(resolve => setTimeout(resolve, 10000)); + await confirmCreation(createAndSearchConfig, request, dataToCreate, creationTime, activities); + } + await generateProcessedFileAndPersist(request, localizationMap); +} + +/** + * Processes generic requests such as create or validate. + * @param request The HTTP request object. + */ +async function processGenericRequest(request: any, localizationMap?: { [key: string]: string }) { + // Process generic requests + if (request?.body?.ResourceDetails?.action == "create") { + await processCreate(request, localizationMap) + } + else { + await processValidate(request, localizationMap) + } +} + +async function handleResouceDetailsError(request: any, error: any) { + var stringifiedError: any; + if (error?.description || error?.message) { + stringifiedError = JSON.stringify({ + status: error.status || '', + code: error.code || '', + description: error.description || '', + message: error.message || '' + }); + } + else { + if (typeof error == "object") + stringifiedError = JSON.stringify(error); + else { + stringifiedError = 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 + }; + const persistMessage: any = { ResourceDetails: request.body.ResourceDetails } + if (request?.body?.ResourceDetails?.action == "create") { + persistMessage.ResourceDetails.additionalDetails = { error: stringifiedError } + } + await produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC); + } + 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)); + const activityObject = request?.body?.Activities; + await produceModifiedMessages(activityObject, config?.kafka?.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC); + } +} + +async function persistCreationProcess(request: any, status: any) { + if (request?.body?.ResourceDetails?.type == "facility") { + await persistTrack(request?.body?.ResourceDetails?.campaignId, processTrackTypes.facilityCreation, status); + } + else if (request?.body?.ResourceDetails?.type == "user") { + await persistTrack(request?.body?.ResourceDetails?.campaignId, processTrackTypes.staffCreation, status); + } +} + +async function processAfterValidation(dataFromSheet: any, createAndSearchConfig: any, request: any, localizationMap?: { [key: string]: string }) { + await persistCreationProcess(request, processTrackStatuses.inprogress) + try { + const typeData = await convertToTypeData(request, dataFromSheet, createAndSearchConfig, request.body, localizationMap) + request.body.dataToCreate = typeData.createData; + request.body.dataToSearch = typeData.searchData; + await processSearchAndValidation(request, createAndSearchConfig, dataFromSheet) + await reorderBoundariesOfDataAndValidate(request, localizationMap) + if (createAndSearchConfig?.createBulkDetails && request.body.ResourceDetails.status != "invalid") { + _.set(request.body, createAndSearchConfig?.createBulkDetails?.createPath, request?.body?.dataToCreate); + const params: any = getParamsViaElements(createAndSearchConfig?.createBulkDetails?.createElements, request); + changeBodyViaElements(createAndSearchConfig?.createBulkDetails?.createElements, request) + await performAndSaveResourceActivity(request, createAndSearchConfig, params, request.body.ResourceDetails.type, localizationMap); + } + else if (request.body.ResourceDetails.status == "invalid") { + await generateProcessedFileAndPersist(request, localizationMap); + } + } catch (error: any) { + console.log(error) + await persistCreationProcess(request, processTrackStatuses.failed) + await handleResouceDetailsError(request, error) + } + await persistCreationProcess(request, processTrackStatuses.completed) +} + +/** + * Processes the creation of resources. + * @param request The HTTP request object. + */ +async function processCreate(request: any, localizationMap?: any) { + // Process creation of resources + const type: string = request.body.ResourceDetails.type; + const tenantId = request?.body?.ResourceDetails?.tenantId; + if (type == "boundary") { + boundaryBulkUpload(request, localizationMap); + } + else { + // console.log(`Source is MICROPLAN -->`, source); + let createAndSearchConfig: any; + createAndSearchConfig = createAndSearch[type]; + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignType = responseFromCampaignSearch?.CampaignDetails[0]?.projectType; + if (checkIfSourceIsMicroplan(request?.body?.ResourceDetails)) { + logger.info(`Data create Source is MICROPLAN`); + if (createAndSearchConfig?.parseArrayConfig?.parseLogic) { + createAndSearchConfig.parseArrayConfig.parseLogic = createAndSearchConfig.parseArrayConfig.parseLogic.map( + (item: any) => { + if (item.sheetColumn === "E") { + item.sheetColumnName += `_${campaignType}`; + } + return item; + } + ); + } + } + + const dataFromSheet = await getDataFromSheet(request, request?.body?.ResourceDetails?.fileStoreId, request?.body?.ResourceDetails?.tenantId, createAndSearchConfig, undefined, localizationMap) + let schema: any; + + if (type == "facility") { + logger.info("Fetching schema to validate the created data for type: " + type); + const mdmsResponse = await callMdmsTypeSchema(request, tenantId, type); + schema = mdmsResponse + } + else if (type == "facilityMicroplan") { + const mdmsResponse = await callMdmsTypeSchema(request, tenantId, "facility", "microplan"); + schema = mdmsResponse + logger.info("Appending project type to capacity for microplan " + campaignType); + schema = await appendProjectTypeToCapacity(schema, campaignType); + } + else if (type == "user") { + logger.info("Fetching schema to validate the created data for type: " + type); + const mdmsResponse = await callMdmsTypeSchema(request, tenantId, type); + schema = mdmsResponse + } + 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) + } +} + +/** + * Creates resources for a project campaign. + * @param request The HTTP request object. + */ +async function createProjectCampaignResourcData(request: any) { + await persistTrack(request.body.CampaignDetails.id, processTrackTypes.triggerResourceCreation, processTrackStatuses.inprogress); + try { + // Create resources for a project campaign + if (request?.body?.CampaignDetails?.action == "create" && request?.body?.CampaignDetails?.resources) { + for (const resource of request?.body?.CampaignDetails?.resources) { + if (resource.type != "boundaryWithTarget") { + const resourceDetails = { + type: resource.type, + fileStoreId: resource.filestoreId, + tenantId: request?.body?.CampaignDetails?.tenantId, + action: "create", + hierarchyType: request?.body?.CampaignDetails?.hierarchyType, + additionalDetails: {}, + campaignId: request?.body?.CampaignDetails?.id + }; + logger.info(`Creating the resources for type ${resource.type}`) + logger.debug("resourceDetails " + getFormattedStringForDebug(resourceDetails)) + const createRequestBody = { + RequestInfo: request.body.RequestInfo, + ResourceDetails: resourceDetails + } + const req = replicateRequest(request, createRequestBody) + const res: any = await createDataService(req) + if (res?.id) { + resource.createResourceId = res?.id + } + } + } + } + } catch (error: any) { + console.log(error) + await persistTrack(request?.body?.CampaignDetails?.id, processTrackTypes.triggerResourceCreation, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + throw new Error(error) + } + await persistTrack(request.body.CampaignDetails.id, processTrackTypes.triggerResourceCreation, processTrackStatuses.completed); +} + +async function confirmProjectParentCreation(request: any, projectId: any) { + const searchBody = { + RequestInfo: request.body.RequestInfo, + Projects: [ + { + id: projectId, + tenantId: request.body.CampaignDetails.tenantId + } + ] + } + const params = { + tenantId: request.body.CampaignDetails.tenantId, + offset: 0, + limit: 5 + } + var projectFound = false; + var retry = 6; + while (!projectFound && retry >= 0) { + const response = await httpRequest(config.host.projectHost + config.paths.projectSearch, searchBody, params); + if (response?.Project?.[0]) { + projectFound = true; + } + else { + logger.info("Project not found. Waiting for 1 seconds"); + retry = retry - 1 + logger.info(`Waiting for ${retry} for 1 more second`); + await new Promise(resolve => setTimeout(resolve, 1000)); + } + } + if (!projectFound) { + throwError("PROJECT", 500, "PROJECT_CONFIRMATION_FAILED", "Project confirmation failed, for the project with id " + projectId); + } +} + +async function projectCreate(projectCreateBody: any, request: any) { + logger.info("Project creation 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)) + 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 + } + else { + throwError("PROJECT", 500, "PROJECT_CREATION_FAILED", "Project creation failed, for the request: " + JSON.stringify(projectCreateBody)); + } +} + +function generateHierarchyList(data: any[], parentChain: any = []) { + let result: any[] = []; + + // Iterate over each boundary in the current level + for (let boundary of data) { + let currentChain = [...parentChain, boundary.code]; + + // Add the current chain to the result + result.push(currentChain.join(',')); + + // If there are children, recursively call the function + if (boundary.children && boundary.children.length > 0) { + let childResults = generateHierarchyList(boundary.children, currentChain); + result = result.concat(childResults); + } + } + return result; + +} + +const getHierarchy = async (request: any, tenantId: string, hierarchyType: string) => { + const url = `${config.host.boundaryHost}${config.paths.boundaryHierarchy}`; + + // Create request body + const requestBody = { + "RequestInfo": request?.body?.RequestInfo, + "BoundaryTypeHierarchySearchCriteria": { + "tenantId": tenantId, + "limit": 5, + "offset": 0, + "hierarchyType": hierarchyType + } + }; + + const response = await httpRequest(url, requestBody); + const boundaryList = response?.BoundaryHierarchy?.[0].boundaryHierarchy; + return generateHierarchy(boundaryList); +}; + +const getHeadersOfBoundarySheet = async (fileUrl: string, sheetName: string, getRow = false, localizationMap?: any) => { + const localizedBoundarySheetName = getLocalizedName(sheetName, localizationMap); + const workbook: any = await getExcelWorkbookFromFileURL(fileUrl, localizedBoundarySheetName); + + const worksheet = workbook.getWorksheet(localizedBoundarySheetName); + 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'); +} + + +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); + return projectTypeSearchResponse; + } catch (error: any) { + logger.error(`Error while searching for campaign details: ${error.message}`); + throwError("COMMON", 400, "RESPONSE_NOT_FOUND_ERROR", error?.message) + } +} + +export { + enrichCampaign, + getAllFacilities, + getFacilitiesViaIds, + confirmCreation, + getParamsViaElements, + changeBodyViaElements, + processGenericRequest, + createProjectCampaignResourcData, + processCreate, + projectCreate, + generateHierarchyList, + getHierarchy, + getHeadersOfBoundarySheet, + handleResouceDetailsError, + getCampaignSearchResponse, + confirmProjectParentCreation +}; diff --git a/health-services/project-factory/src/server/api/genericApis.ts b/health-services/project-factory/src/server/api/genericApis.ts new file mode 100644 index 00000000000..c7fa9ced8e0 --- /dev/null +++ b/health-services/project-factory/src/server/api/genericApis.ts @@ -0,0 +1,1260 @@ +// Import necessary modules and libraries +import config from "../config"; // Import configuration settings +import FormData from "form-data"; // Import FormData for handling multipart/form-data requests +import { defaultheader, httpRequest } from "../utils/request"; // Import httpRequest function for making HTTP requests +import { getFormattedStringForDebug, logger } from "../utils/logger"; // Import logger for logging +import { correctParentValues, findMapValue, generateActivityMessage, getBoundaryRelationshipData, getDataSheetReady, getLocalizedHeaders, sortCampaignDetails, throwError } from "../utils/genericUtils"; // Import utility functions +import { extractCodesFromBoundaryRelationshipResponse, generateFilteredBoundaryData, getConfigurableColumnHeadersBasedOnCampaignType, getFiltersFromCampaignSearchResponse, getLocalizedName } from '../utils/campaignUtils'; // Import utility functions +import { getCampaignSearchResponse, getHierarchy } from './campaignApis'; +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) +const getTargetWorkbook = async (fileUrl: string, localizationMap?: any) => { + // Define headers for HTTP request + + const workbook: any = await getExcelWorkbookFromFileURL(fileUrl, ""); + + // Get the main sheet name (assuming it's the second sheet) + const mainSheetName = workbook.getWorksheet(1).name; + const localizedMainSheet = getLocalizedName(mainSheetName, localizationMap); + + // Check if the main sheet exists in the workbook + if (!workbook.getWorksheet(localizedMainSheet)) { + throwError( + "FILE", + 400, + "INVALID_SHEETNAME", + `Sheet with name "${localizedMainSheet}" is not present in the file.` + ); + } + + // Return the workbook + return workbook; +}; + +function getJsonData(sheetData: any, getRow = false, getSheetName = false, sheetName = "sheet1") { + const jsonData: any[] = []; + const headers = sheetData[0]; // Extract the headers from the first row + + for (let i = 1; i < sheetData.length; i++) { + const rowData: any = {}; + const row = sheetData[i]; + if (row) { + for (let j = 0; j < headers.length; j++) { + const key = headers[j]; + const value = row[j] === undefined || row[j] === "" ? "" : row[j]; + if (value || value === 0) { + rowData[key] = value; + } + } + if (Object.keys(rowData).length > 0) { + if (getRow) rowData["!row#number!"] = i + 1; + if (getSheetName) rowData["!sheet#name!"] = sheetName; + jsonData.push(rowData); + } + } + }; + return jsonData; +} + +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 +const getSheetData = async ( + fileUrl: string, + sheetName: string, + getRow = false, + createAndSearchConfig?: any, + localizationMap?: { [key: string]: string } +) => { + // 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); + + // Collect sheet data by iterating through rows and cells + const sheetData = getSheetDataFromWorksheet(worksheet); + const jsonData = getJsonData(sheetData, getRow); + return jsonData; +}; + +// Helper function to extract raw cell value +function getRawCellValue(cell: any) { + if (cell.value && typeof cell.value === 'object') { + if ('richText' in cell.value) { + // Handle rich text + return cell.value.richText.map((rt: any) => rt.text).join(''); + } else if ('formula' in cell.value) { + // Get the result of the formula + return cell.value.result; + } else if ('error' in cell.value) { + // Get the error value + return cell.value.error; + } else if (cell.value instanceof Date) { + // Handle date values + return cell.value.toISOString(); + } else { + // Return as-is for other object types + return cell.value; + } + } + return cell.value; // Return raw value for plain strings, numbers, etc. +} + +const getTargetSheetData = async ( + fileUrl: string, + getRow = false, + getSheetName = false, + localizationMap?: any +) => { + const workbook = await getTargetWorkbook(fileUrl, localizationMap); + const sheetNames: string[] = []; + workbook.eachSheet((worksheet: any) => { + sheetNames.push(worksheet.name); + }); + const localizedSheetNames = getLocalizedHeaders(sheetNames, localizationMap); + + const workbookData: { [key: string]: any[] } = {}; // Object to store data from each sheet + + for (const sheetName of localizedSheetNames) { + const worksheet = workbook.getWorksheet(sheetName); + const sheetData = getSheetDataFromWorksheet(worksheet); + workbookData[sheetName] = getJsonData(sheetData, getRow, getSheetName, sheetName); + } + return workbookData; +}; + +const getTargetSheetDataAfterCode = async ( + fileUrl: string, + getRow = false, + getSheetName = false, + codeColumnName = "Boundary Code", + localizationMap?: any +) => { + const workbook = await getTargetWorkbook(fileUrl, localizationMap); + const sheetNames: string[] = []; + workbook.eachSheet((worksheet: any) => { + sheetNames.push(worksheet.name); + }); + const localizedSheetNames = getLocalizedHeaders(sheetNames, localizationMap); + + const workbookData: { [key: string]: any[] } = {}; // Object to store data from each sheet + + for (const sheetName of localizedSheetNames) { + const worksheet = workbook.getWorksheet(sheetName); + const sheetData = getSheetDataFromWorksheet(worksheet); + + // Find the target column index where the first row value matches codeColumnName + const firstRow = sheetData[0]; + let targetColumnIndex = -1; + for (let colIndex = 1; colIndex < firstRow.length; colIndex++) { + if (firstRow[colIndex] === codeColumnName) { + targetColumnIndex = colIndex; + break; + } + } + + if (targetColumnIndex === -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 + + let rowData: any = { [codeColumnName]: row[targetColumnIndex] }; + + // Add integer values in the target column for the current row + let sum = 0; + for (let colIndex = targetColumnIndex + 1; colIndex < row.length; colIndex++) { + const value = row[colIndex]; + if (typeof value === 'number' && Number.isInteger(value)) { + sum += value; + } + } + + // Add the sum to the row data + rowData['Target at the Selected Boundary level'] = sum; + return rowData; + }).filter(Boolean); // Remove null entries + + workbookData[sheetName] = processedData; + } + + return workbookData; +}; + + +// Function to search MDMS for specific unique identifiers +const searchMDMS: any = async ( + uniqueIdentifiers: any[], + schemaCode: string, + requestinfo: any +) => { + // Check if unique identifiers are provided + if (!uniqueIdentifiers) { + return; + } + + // Construct API URL for MDMS search + const apiUrl = config.host.mdms + config.paths.mdms_search; + + // Construct request data for MDMS search + const data = { + MdmsCriteria: { + tenantId: requestinfo?.userInfo?.tenantId, + uniqueIdentifiers: uniqueIdentifiers, + schemaCode: schemaCode, + }, + RequestInfo: requestinfo, + }; + + // Make HTTP request to MDMS API + const result = await httpRequest( + apiUrl, + data, + undefined, + undefined, + undefined + ); + + // Log search result + logger.info("Template search Result : " + JSON.stringify(result)); + + // Return search result + return result; +}; + +// Function to generate a campaign number +const getCampaignNumber: any = async ( + requestBody: any, + idFormat: String, + idName: string, + tenantId: string +) => { + // Construct request data + const data = { + RequestInfo: requestBody?.RequestInfo, + idRequests: [ + { + idName: idName, + tenantId: tenantId, + format: idFormat, + }, + ], + }; + + // Construct URL for ID generation service + const idGenUrl = config.host.idGenHost + config.paths.idGen; + + // Make HTTP request to ID generation service + const result = await httpRequest( + idGenUrl, + data, + undefined, + undefined, + undefined, + undefined + ); + + // Return generated campaign number + if (result?.idResponses?.[0]?.id) { + return result?.idResponses?.[0]?.id; + } + + // Throw error if ID generation fails + throwError("COMMON", 500, "IDGEN_ERROR"); +}; + +// Function to generate a resource number +const getResouceNumber: any = async ( + RequestInfo: any, + idFormat: String, + idName: string +) => { + // Construct request data + const data = { + RequestInfo, + idRequests: [ + { + idName: idName, + tenantId: RequestInfo?.userInfo?.tenantId, + format: idFormat, + }, + ], + }; + + // Construct URL for ID generation service + const idGenUrl = config.host.idGenHost + config.paths.idGen; + + try { + // Make HTTP request to ID generation service + const result = await httpRequest( + idGenUrl, + data, + undefined, + undefined, + undefined, + undefined + ); + + // Return generated resource number + if (result?.idResponses?.[0]?.id) { + return result?.idResponses?.[0]?.id; + } + + // Return null if ID generation fails + return result; + } catch (error: any) { + // Log error if ID generation fails + logger.error("Error: " + error); + + // Return error + return error; + } +}; + +// Function to get schema definition based on code and request info +const getSchema: any = async (code: string, RequestInfo: any) => { + const data = { + RequestInfo, + SchemaDefCriteria: { + tenantId: RequestInfo?.userInfo?.tenantId, + limit: 200, + codes: [code], + }, + }; + const mdmsSearchUrl = config.host.mdms + config.paths.mdmsSchema; + + try { + const result = await httpRequest( + mdmsSearchUrl, + data, + undefined, + undefined, + undefined, + undefined + ); + return result?.SchemaDefinitions?.[0]?.definition; + } catch (error: any) { + logger.error("Error: " + error); + return error; + } +}; + +// Function to get count from response data +const getCount: any = async ( + responseData: any, + request: any, + response: any +) => { + try { + // Extract host and URL from response data + const host = responseData?.host; + const url = responseData?.searchConfig?.countUrl; + + // Extract request information + const requestInfo = { RequestInfo: request?.body?.RequestInfo }; + + // Make HTTP request to get count + const result = await httpRequest( + host + url, + requestInfo, + undefined, + undefined, + undefined, + undefined + ); + + // Extract count from result using lodash + const count = _.get(result, responseData?.searchConfig?.countPath); + + return count; // Return the count + } catch (error: any) { + // Log and throw error if any + logger.error("Error: " + error); + throw error; + } +}; + +// Function to create Excel sheet and upload it +async function createAndUploadFile( + updatedWorkbook: any, + request: any, + tenantId?: any +) { + // 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, + } + ); + + // Extract response data + const responseData = fileCreationResult?.files; + if (!responseData) { + throw new Error( + "Error while uploading excel 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[] = []; + + // Iterate over each boundary in the current level + for (let boundary of data) { + let currentChain = [...parentChain, boundary.code]; + + // Add the current chain to the result + result.push(currentChain.join(",")); + + // If there are children, recursively call the function + if (boundary.children.length > 0) { + let childResults = generateHierarchyList(boundary.children, currentChain); + result = result.concat(childResults); + } + } + return result; // Return the hierarchy list +} + +// Function to generate hierarchy from boundaries +function generateHierarchy(boundaries: any[]) { + // Create an object to store boundary types and their parents + const parentMap: any = {}; + + // Populate the object with boundary types and their parents + for (const boundary of boundaries) { + parentMap[boundary.boundaryType] = boundary.parentBoundaryType; + } + + // Traverse the hierarchy to generate the hierarchy list + const hierarchyList = []; + for (const boundaryType in parentMap) { + if (Object.prototype.hasOwnProperty.call(parentMap, boundaryType)) { + const parentBoundaryType = parentMap[boundaryType]; + if (parentBoundaryType === null) { + // This boundary type has no parent, add it to the hierarchy list + hierarchyList.push(boundaryType); + // Traverse its children recursively + traverseChildren(boundaryType, parentMap, hierarchyList); + } + } + } + return hierarchyList; // Return the hierarchy list +} + +// Recursive function to traverse children and generate hierarchy +function traverseChildren(parent: any, parentMap: any, hierarchyList: any[]) { + for (const boundaryType in parentMap) { + if (Object.prototype.hasOwnProperty.call(parentMap, boundaryType)) { + const parentBoundaryType = parentMap[boundaryType]; + if (parentBoundaryType === parent) { + // This boundary type has the current parent, add it to the hierarchy list + hierarchyList.push(boundaryType); + // Traverse its children recursively + traverseChildren(boundaryType, parentMap, hierarchyList); + } + } + } +} + +// Function to create an Excel sheet +async function createExcelSheet(data: any, headers: any) { + var rows = [headers, ...data]; + return rows; +} + +// Function to handle getting boundary codes +async function getAutoGeneratedBoundaryCodesHandler(boundaryList: any, childParentMap: Map<{ key: string; value: string; }, { key: string; value: string; } | null>, elementCodesMap: any, countMap: any, request: any) { + try { + // Get updated element codes map + logger.info("Auto Generation of Boundary code begins for the user uploaded sheet") + const updatedelementCodesMap = await getAutoGeneratedBoundaryCodes(boundaryList, childParentMap, elementCodesMap, countMap, request); + return updatedelementCodesMap; // Return the updated element codes map + } catch (error) { + // Log and propagate the error + console.error("Error in getBoundaryCodesHandler:", error); + throw error; + } +} + +/** + * Function to generate auto-generated boundary codes based on boundary list, child-parent mapping, + * element codes map, count map, and request information. + * @param boundaryList List of boundary data + * @param childParentMap Map of child-parent relationships + * @param elementCodesMap Map of element codes + * @param countMap Map of counts for each element + * @param request HTTP request object + * @returns Updated element codes map + */ +async function getAutoGeneratedBoundaryCodes(boundaryList: any, childParentMap: any, elementCodesMap: any, countMap: any, request: any) { + // Initialize an array to store column data + const columnsData: { key: string, value: string }[][] = []; + // Extract unique elements from each column + for (const row of boundaryList) { + row.forEach((element: any, index: any) => { + if (!columnsData[index]) { + columnsData[index] = []; + } + const existingElement = columnsData[index].find((existing: any) => _.isEqual(existing, element)); + if (!existingElement) { + columnsData[index].push(element); + } + }); + } + + // Iterate over columns to generate boundary codes + for (let i = 0; i < columnsData.length; i++) { + const column = columnsData[i]; + for (const element of column) { + if (!findMapValue(elementCodesMap, element)) { + const 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 + 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); + } + } + } + } + return elementCodesMap; // Return the updated element codes map +} + +/** + * Function to generate an element code based on sequence, parent code, and element. + * @param sequence Sequence number + * @param 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, parentElement: any, parentBoundaryCode: any, element: any, excludeBoundaryNameAtLastFromBoundaryCodes?: any, childParentMap?: any, elementCodesMap?: any) { + // Pad single-digit numbers with leading zero + 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(); +} + +/** + * Asynchronously retrieves boundary sheet data based on the provided request. + * @param request The HTTP request object. + * @returns Boundary sheet data. + */ +async function getBoundarySheetData( + request: any, + localizationMap?: { [key: string]: string } +) { + // Retrieve boundary data based on the request parameters + const params = { + ...request?.query, + includeChildren: true, + }; + const hierarchyType = request?.query?.hierarchyType; + logger.info( + `processing boundary data generation for hierarchyType : ${hierarchyType}` + ); + const boundaryData = await getBoundaryRelationshipData(request, params); + if (!boundaryData || boundaryData.length === 0) { + logger.info(`boundary data not found for hierarchyType : ${hierarchyType}`); + const hierarchy = await getHierarchy( + request, + request?.query?.tenantId, + hierarchyType + ); + const modifiedHierarchy = hierarchy.map((ele) => + `${hierarchyType}_${ele}`.toUpperCase() + ); + const localizedHeadersUptoHierarchy = getLocalizedHeaders( + modifiedHierarchy, + localizationMap + ); + const headerColumnsAfterHierarchy = await getConfigurableColumnHeadersBasedOnCampaignType(request, localizationMap); + const headers = [...localizedHeadersUptoHierarchy, ...headerColumnsAfterHierarchy]; + // create empty sheet if no boundary present in system + // const localizedBoundaryTab = getLocalizedName( + // getBoundaryTabName(), + // localizationMap + // ); + logger.info(`generated a empty template for boundary`); + return await createExcelSheet( + boundaryData, + headers + ); + } else { + let Filters: any = {}; + if (request?.body?.Filters && request?.body?.Filters.boundaries && Array.isArray(request?.body?.Filters.boundaries) && request?.body?.Filters.boundaries.length > 0) { + Filters = { + Filters: { + boundaries: request.body.Filters.boundaries.map((boundary: any) => ({ + ...boundary, + boundaryType: boundary.type // Adding boundaryType field + })) + } + }; + } + else { + // logger.info("boundaryData for sheet " + JSON.stringify(boundaryData)) + const responseFromCampaignSearch = + await getCampaignSearchResponse(request); + Filters = getFiltersFromCampaignSearchResponse(responseFromCampaignSearch) + } + if (Filters?.Filters && Filters.Filters.boundaries && Array.isArray(Filters.Filters.boundaries) && Filters.Filters.boundaries.length > 0) { + const filteredBoundaryData = await generateFilteredBoundaryData( + request, + Filters + ); + return await getDataSheetReady( + filteredBoundaryData, + request, + localizationMap + ); + } + else { + return await getDataSheetReady(boundaryData, request, localizationMap); + } + } +} + +async function createStaff(resouceBody: any) { + // Create staff + const staffCreateUrl = + `${config.host.projectHost}` + `${config.paths.staffCreate}`; + logger.info("Project staff Creation : API :" + config.paths.staffCreate); + + const staffResponse = await httpRequest( + staffCreateUrl, + resouceBody, + undefined, + "post", + undefined, + undefined, + undefined, + false + ); + logger.info("Project Staff mapping created"); + logger.debug( + "Project Staff mapping response " + + getFormattedStringForDebug(staffResponse) + ); + // validateStaffResponse(staffResponse); +} + +/** + * Asynchronously creates project resources based on the provided resource body. + * @param resouceBody The resource body. + */ +async function createProjectResource(resouceBody: any) { + // Create project resources + const projectResourceCreateUrl = + `${config.host.projectHost}` + `${config.paths.projectResourceCreate}`; + logger.info("Project Resource Creation : API : " + config.paths.projectResourceCreate); + + const projectResourceResponse = await httpRequest( + projectResourceCreateUrl, + resouceBody, + undefined, + "post", + undefined, + undefined, + undefined, + false + ); + logger.debug("Project Resource Created"); + logger.debug( + "Project Resource Creation response :: " + + getFormattedStringForDebug(projectResourceResponse) + ); + // validateProjectResourceResponse(projectResourceResponse); +} + +/** + * Asynchronously creates project facilities based on the provided resource body. + * @param resouceBody The resource body. + */ +async function createProjectFacility(resouceBody: any) { + // Create project facilities + const projectFacilityCreateUrl = + `${config.host.projectHost}` + `${config.paths.projectFacilityCreate}`; + logger.info("Project Facility Creation : API :" + config.paths.projectFacilityCreate); + + const projectFacilityResponse = await httpRequest( + projectFacilityCreateUrl, + resouceBody, + undefined, + "post", + undefined, + undefined, + undefined, + false + ); + logger.info("Project Facility Created"); + logger.debug( + "Project Facility Creation response" + + getFormattedStringForDebug(projectFacilityResponse) + ); + // validateProjectFacilityResponse(projectFacilityResponse); +} + +// 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); +}; + +// 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); +}; + +// 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); +}; + + +/** + * Asynchronously creates related entities such as staff, resources, and facilities based on the provided resources, tenant ID, project ID, start date, end date, and resource body. + * @param resources List of resources. + * @param tenantId The tenant ID. + * @param projectId The project ID. + * @param startDate The start date. + * @param endDate The end date. + * @param resouceBody The resource body. + */ +async function createRelatedEntity( + createRelatedEntityArray: any[], + CampaignDetails: any, + requestBody: any +) { + 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) + } + } + const mappingObject: any = { mappingArray: mappingArray, CampaignDetails: CampaignDetails, RequestInfo: requestBody?.RequestInfo } + await processMapping(mappingObject) +} + + +/** + * Asynchronously creates related resources based on the provided request body. + * @param requestBody The request body. + */ +async function createRelatedResouce(requestBody: any) { + const id = requestBody?.Campaign?.id; + 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 + ); +} + +/** + * Asynchronously creates boundary entities based on the provided request and boundary map. + * @param request The HTTP request object. + * @param boundaryMap Map of boundary names to codes. + */ +async function createBoundaryEntities(request: any, boundaryMap: Map) { + try { + const updatedBoundaryMap: Array<{ key: string, value: string }> = Array.from(boundaryMap).map(([key, value]) => ({ key: key.value, value: value })); + // Create boundary entities + const requestBody = { "RequestInfo": request.body.RequestInfo } as { RequestInfo: any; Boundary?: any }; + const boundaries: any[] = []; + const codesFromResponse: any = []; + const boundaryCodes: any[] = []; + Array.from(boundaryMap.entries()).forEach(([, boundaryCode]) => { + boundaryCodes.push(boundaryCode); + }); + const boundaryEntitiesCreated: any[] = []; + const boundaryEntityCreateChunkSize = 200; + const chunkSize = 20; + const boundaryCodeChunks = []; + for (let i = 0; i < boundaryCodes.length; i += chunkSize) { + boundaryCodeChunks.push(boundaryCodes.slice(i, i + chunkSize)); + } + + for (const chunk of boundaryCodeChunks) { + const string = chunk.join(', '); + const boundaryEntityResponse = await httpRequest(config.host.boundaryHost + config.paths.boundaryServiceSearch, request.body, { tenantId: request?.body?.ResourceDetails?.tenantId, codes: string }); + const boundaryCodesFromResponse = boundaryEntityResponse.Boundary.flatMap((boundary: any) => boundary.code.toString()); + codesFromResponse.push(...boundaryCodesFromResponse); + } + + const codeSet = new Set(codesFromResponse);// Creating a set and filling it with the codes from the response + for (const { key: boundaryName, value: boundaryCode } of updatedBoundaryMap) { + if (!codeSet.has(boundaryCode.toString())) { + const boundary = { + tenantId: request?.body?.ResourceDetails?.tenantId, + code: boundaryCode, + geometry: null, + additionalDetails: { + name: boundaryName + } + }; + boundaries.push(boundary); + } + }; + if (!(boundaries.length === 0)) { + for (let i = 0; i < boundaries.length; i += boundaryEntityCreateChunkSize) { + requestBody.Boundary = boundaries.slice(i, i + boundaryEntityCreateChunkSize); + const response = await httpRequest(`${config.host.boundaryHost}boundary-service/boundary/_create`, requestBody, {}, 'POST',); + boundaryEntitiesCreated.push(response) + } + logger.info('Boundary entities created'); + logger.debug('Boundary entities response: ' + getFormattedStringForDebug(boundaryEntitiesCreated)); + } + else { + // throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary entity already present in the system"); + logger.info("Boundary Entities are already in the system") + } + } catch (error) { + throwError("COMMMON", 500, "INTERNAL_SERVER_ERROR", "Error while Boundary Entity Creation") + } +} + +async function confirmBoundaryParentCreation(request: any, code: any) { + if (code) { + const searchBody = { + RequestInfo: request.body.RequestInfo, + } + const params: any = { + hierarchyType: request?.body?.ResourceDetails?.hierarchyType, + tenantId: request?.body?.ResourceDetails?.tenantId, + codes: code + } + var retry = 6; + var boundaryFound = false; + const header = { + ...defaultheader, + cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, + } + while (!boundaryFound && retry >= 0) { + const response = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, searchBody, params, undefined, undefined, header); + if (response?.TenantBoundary?.[0].boundary?.[0]) { + boundaryFound = true; + } + else { + logger.info("Boundary not found. Waiting for 1 seconds"); + retry = retry - 1 + await new Promise(resolve => setTimeout(resolve, 1000)); + } + } + if (!boundaryFound) { + throwError("BOUNDARY", 500, "INTERNAL_SERVER_ERROR", "Boundary creation failed, for the boundary with code " + code); + } + } +} + +/** + * Asynchronously creates boundary relationships based on the provided request, boundary type map, and modified child-parent map. + * @param request The HTTP request object. + * @param boundaryTypeMap Map of boundary codes to types. + * @param modifiedChildParentMap Modified child-parent map. + */ +async function createBoundaryRelationship(request: any, boundaryMap: Map<{ key: string, value: string }, string>, modifiedChildParentMap: Map) { + try { + + const updatedBoundaryMap: Array<{ key: string, value: string }> = Array.from(boundaryMap).map(([key, value]) => ({ key: value, value: key.key })); + + let activityMessage: any[] = []; + const requestBody = { "RequestInfo": request.body.RequestInfo } as { RequestInfo: any; BoundaryRelationship?: any }; + const url = `${config.host.boundaryHost}${config.paths.boundaryRelationship}`; + const params = { + "type": request?.body?.ResourceDetails?.type, + "tenantId": request?.body?.ResourceDetails?.tenantId, + "boundaryType": null, + "codes": null, + "includeChildren": true, + "hierarchyType": request?.body?.ResourceDetails?.hierarchyType + }; + const header = { + ...defaultheader, + cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, + } + + const boundaryRelationshipResponse = await httpRequest(url, request.body, params, undefined, undefined, header); + const boundaryData = boundaryRelationshipResponse?.TenantBoundary?.[0]?.boundary; + const allCodes = extractCodesFromBoundaryRelationshipResponse(boundaryData); + + let flag = 1; + + for (const { key: boundaryCode, value: boundaryType } of updatedBoundaryMap) { + if (!allCodes.has(boundaryCode)) { + const boundary = { + tenantId: request?.body?.ResourceDetails?.tenantId, + boundaryType: boundaryType, + code: boundaryCode, + hierarchyType: request?.body?.ResourceDetails?.hierarchyType, + parent: modifiedChildParentMap.get(boundaryCode) || null + }; + + flag = 0; + requestBody.BoundaryRelationship = boundary; + await confirmBoundaryParentCreation(request, modifiedChildParentMap.get(boundaryCode) || null); + try { + const response = await httpRequest(`${config.host.boundaryHost}${config.paths.boundaryRelationshipCreate}`, requestBody, {}, 'POST', undefined, undefined, true); + + if (!response.TenantBoundary || !Array.isArray(response.TenantBoundary) || response.TenantBoundary.length === 0) { + throwError("BOUNDARY", 500, "BOUNDARY_RELATIONSHIP_CREATE_ERROR"); + } + logger.info(`Boundary relationship created for boundaryType :: ${boundaryType} & boundaryCode :: ${boundaryCode} `); + + const newRequestBody = JSON.parse(JSON.stringify(request.body)); + activityMessage.push(await generateActivityMessage(request?.body?.ResourceDetails?.tenantId, request.body, newRequestBody, response, request?.body?.ResourceDetails?.type, `${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); + throw error; + } + } + }; + + if (flag === 1) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary already present in the system"); + } + + request.body = { + ...request.body, + Activities: activityMessage + }; + } catch (error: any) { + const errorCode = error.code || "INTERNAL_SERVER_ERROR"; + const errorMessage = error.description || "Error while boundary relationship create"; + logger.error(`Error in createBoundaryRelationship: ${errorMessage}`, error); + throwError("COMMON", 500, errorCode, errorMessage); + } +} + + + +async function callMdmsData( + request: any, + moduleName: string, + masterName: string, + tenantId: string +) { + const { RequestInfo = {} } = request?.body || {}; + const requestBody = { + RequestInfo, + MdmsCriteria: { + tenantId: tenantId, + moduleDetails: [ + { + moduleName: moduleName, + masterDetails: [ + { + name: masterName, + }, + ], + }, + ], + }, + }; + const url = config.host.mdms + config.paths.mdms_v1_search; + const response = await httpRequest(url, requestBody, { tenantId: tenantId }); + return response; +} + +function enrichSchema(data: any, properties: any, required: any, columns: any, unique: any, columnsNotToBeFreezed: any, errorMessage: any) { + + // Sort columns based on orderNumber, using name as tie-breaker if orderNumbers are equal + columns.sort((a: any, b: any) => { + if (a.orderNumber === b.orderNumber) { + return a.name.localeCompare(b.name); + } + return a.orderNumber - b.orderNumber; + }); + + required.sort((a: any, b: any) => { + if (a.orderNumber === b.orderNumber) { + return a.name.localeCompare(b.name); + } + return a.orderNumber - b.orderNumber; + }); + + const sortedRequiredColumns = required.map((column: any) => column.name); + + // Extract sorted property names + const sortedPropertyNames = columns.map((column: any) => column.name); + + // Update data with new properties and required fields + data.properties = properties; + data.required = sortedRequiredColumns; + data.columns = sortedPropertyNames; + data.unique = unique; + data.errorMessage = errorMessage; + data.columnsNotToBeFreezed = columnsNotToBeFreezed; +} + +function convertIntoSchema(data: any) { + const properties: any = {}; + const errorMessage: any = {}; + const required: any[] = []; + const columns: any[] = []; + const unique: any[] = []; + const columnsNotToBeFreezed: any[] = []; + + for (const propType of ['enumProperties', 'numberProperties', 'stringProperties']) { + if (data.properties[propType] && Array.isArray(data.properties[propType]) && data.properties[propType]?.length > 0) { + for (const property of data.properties[propType]) { + properties[property?.name] = { + ...property, + type: propType === 'stringProperties' ? 'string' : propType === 'numberProperties' ? 'number' : undefined + }; + if (property?.errorMessage) + errorMessage[property?.name] = property?.errorMessage; + + if (property?.isRequired && required.indexOf(property?.name) === -1) { + required.push({ name: property?.name, orderNumber: property?.orderNumber }); + } + if (property?.isUnique && unique.indexOf(property?.name) === -1) { + unique.push(property?.name); + } + if (!property?.freezeColumn || property?.freezeColumn == false) { + columnsNotToBeFreezed.push(property?.name); + } + + // If orderNumber is missing, default to a very high number + columns.push({ name: property?.name, orderNumber: property?.orderNumber || 9999999999 }); + } + } + } + enrichSchema(data, properties, required, columns, unique, columnsNotToBeFreezed, errorMessage); + return data; +} + + + +async function callMdmsTypeSchema( + request: any, + tenantId: string, + type: any, + campaignType = "all" +) { + const { RequestInfo = {} } = request?.body || {}; + const requestBody = { + RequestInfo, + MdmsCriteria: { + tenantId: tenantId, + uniqueIdentifiers: [ + `${type}.${campaignType}` + ], + schemaCode: "HCM-ADMIN-CONSOLE.adminSchema" + } + }; + const url = config.host.mdmsV2 + config.paths.mdms_v2_search; + const header = { + ...defaultheader, + cachekey: `mdmsv2Seacrh${requestBody?.MdmsCriteria?.tenantId}${campaignType}${type}.${campaignType}${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 schema search"); + } + return convertIntoSchema(response?.mdms?.[0]?.data); +} + +async function getMDMSV1Data(request: any, moduleName: string, masterName: string, tenantId: string) { + const resp: any = await callMdmsData(request, moduleName, masterName, tenantId); + return resp?.["MdmsRes"]?.[moduleName]?.[masterName]; +} + +export { + getAutoGeneratedBoundaryCodes, + getAutoGeneratedBoundaryCodesHandler, + createBoundaryEntities, + createBoundaryRelationship, + getSheetData, + searchMDMS, + getCampaignNumber, + getSchema, + getResouceNumber, + getCount, + getBoundarySheetData, + createAndUploadFile, + createRelatedResouce, + createExcelSheet, + generateHierarchy, + generateHierarchyList, + getTargetWorkbook, + getTargetSheetData, + getTargetSheetDataAfterCode, + callMdmsData, + getMDMSV1Data, + callMdmsTypeSchema, + getSheetDataFromWorksheet, + createStaffHelper, + createProjectFacilityHelper, createProjectResourceHelper +}; diff --git a/health-services/project-factory/src/server/app.ts b/health-services/project-factory/src/server/app.ts new file mode 100644 index 00000000000..a51c4ab15bd --- /dev/null +++ b/health-services/project-factory/src/server/app.ts @@ -0,0 +1,50 @@ +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'; + +class App { + public app: express.Application; + public port: number; + + constructor(controllers: any, port: any) { + this.app = express(); + this.port = port; + + this.initializeMiddlewares(); + this.initializeControllers(controllers); + this.app.use(invalidPathHandler); + } + + private initializeMiddlewares() { + this.app.use(bodyParser.json()); + this.app.use(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': '/', + }, + })); + } + + private initializeControllers(controllers: any) { + controllers.forEach((controller: any) => { + this.app.use(config.app?.contextPath, controller.router); + }); + } + + public listen() { + this.app.listen(this.port, () => { + console.log(`App listening on the port ${this.port}`); + }); + } +} + +export default App; diff --git a/health-services/project-factory/src/server/config/constants.ts b/health-services/project-factory/src/server/config/constants.ts new file mode 100644 index 00000000000..5023c9de00b --- /dev/null +++ b/health-services/project-factory/src/server/config/constants.ts @@ -0,0 +1,163 @@ +import Error from "./error.interface" + +export const CONSTANTS: any = { + ERROR_CODES: { + COMMON: { + UNKNOWN_ERROR: "Unknown error. Check logs", + IDGEN_ERROR: "Error during generating campaign number", + VALIDATION_ERROR: "Validation error", + INTERNAL_SERVER_ERROR: "Internal server error", + INVALID_PAGINATION: "Invalid pagination", + KAFKA_ERROR: "Some error occured in kafka", + SCHEMA_ERROR: " Schema related error", + 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", + INVALID_SHEETNAME: "Invalid sheet name", + STATUS_FILE_CREATION_ERROR: "Error in creating status file", + FETCHING_SHEET_ERROR: "Error occured while fetching sheet data", + INVALID_FILE_ERROR: "Invalid file", + DOWNLOAD_URL_NOT_FOUND: "Not any download URL returned for the given fileStoreId", + INVALID_FILE_FORMAT: "The uploaded file is not a valid excel file (xlsx or xls).", + INVALID_COLUMNS: "Columns are invalid", + FETCHING_COLUMN_ERROR: "Error fetching Column Headers From Schema" + }, + FACILITY: { + FACILITY_SEARCH_FAILED: "Search failed for facility. Check logs", + }, + CAMPAIGN: { + CAMPAIGN_SEARCH_ERROR: "Error in campaign search", + CAMPAIGNNAME_MISMATCH: "CampaignName is not matching", + CAMPAIGN_NOT_FOUND: "Campaign not found", + GENERATION_REQUIRE: "First generate then download", + RESOURCE_CREATION_ERROR: "Some error occured during resource creation", + CAMPAIGN_NAME_ERROR: "Campaign name already exists", + CAMPAIGN_ALREADY_MAPPED: "Campaign is already mapped", + }, + BOUNDARY: { + BOUNDARY_DATA_NOT_FOUND: "No boundary data found in the system.", + BOUNDARY_HIERARCHY_INSERT_ERROR: "Insert boundary hierarchy level wise", + BOUNDARY_SEARCH_ERROR: "Error in boundary search. Check boundary codes", + BOUNDARY_NOT_FOUND: "Boundary not found", + BOUNDARY_SHEET_HEADER_ERROR: "Boundary sheet header error", + BOUNDARY_ENTITY_CREATE_ERROR: "Some error occured during boundary entity creation", + BOUNDARY_RELATIONSHIP_CREATE_ERROR: "Some error occured during boundary relationship creation", + BOUNDARY_TARGET_ERROR: "Target either not present or invalid value", + BOUNDARY_CONFIRMATION_FAILED: "Error in boundary creation and persistence" + }, + PROJECT: { + PROJECT_CREATION_FAILED: "Error occured in project creation", + PROJECT_SEARCH_ERROR: "Error occured during project search , check projectId", + PROJECT_UPDATE_ERROR: "Error occured during project update , check projectId", + PROJECT_CREATION_ERROR: "Some error occured during project creation", + PROJECT_CONFIRMATION_FAILED: "Error occured in project creation and peristence", + }, + MDMS: { + INVALID_README_CONFIG: "Invalid readme config", + MDMS_DATA_NOT_FOUND_ERROR: "Mdms Data not present" + } + } +} + +export const headingMapping: any = { + "userWithBoundary": "USERWITHBOUNDARY_README_MAINHEADER", + "facilityWithBoundary": "FACILITYWITHBOUNDARY_README_MAINHEADER", + "boundary": "BOUNDARY_README_MAINHEADER" +} + +const unknownError = "Unknown Error. Check Logs"; + + +// Retrieves the error message associated with the given error key. +const getMessage = (key: any) => { + // Retrieve the error codes from the CONSTANTS object + const errors = CONSTANTS.ERROR_CODES; + + // Iterate over each module and error key to find the matching error message + for (const moduleKey in errors) { + for (const errorKey in errors[moduleKey]) { + if (key === errorKey) { + return errors[moduleKey][errorKey]; + } + } + } + + // Return 'unknownError' if the error key is not found + return unknownError; +} + +export const campaignStatuses: any = { + drafted: "drafted", + started: "creating", + inprogress: "created", + failed: "failed" +} + +export const resourceDataStatuses: any = { + failed: "failed", + completed: "completed", + invalid: "invalid", + started: "validation-started", + accepted: "data-accepted" +} + +export const generatedResourceStatuses: any = { + inprogress: "inprogress", + failed: "failed", + completed: "completed", + expired: "expired" +} + +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 + const message = CONSTANTS.ERROR_CODES?.[module]?.[key] || getMessage(key) + + // Determine the error code based on whether the message is 'unknownError' or not + const code = message == unknownError ? "UNKNOWN_ERROR" : key + + // Return the error object + return { + code: code, + notFound: true, + message: message + } +} diff --git a/health-services/project-factory/src/server/config/createAndSearch.ts b/health-services/project-factory/src/server/config/createAndSearch.ts new file mode 100644 index 00000000000..8fb63b1be9f --- /dev/null +++ b/health-services/project-factory/src/server/config/createAndSearch.ts @@ -0,0 +1,394 @@ +import config from "."; +const createAndSearch: any = { + "facility": { + requiresToSearchFromSheet: [ + { + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", + searchPath: "Facility.id" + } + ], + boundaryValidation: { + column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY" + }, + sheetSchema: { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "FacilityTemplateSchema", + "type": "object", + "properties": { + "Facility Name": { + "type": "string", + "maxLength": 2000, + "minLength": 1 + }, + "Facility Type": { + // "type": "string", + "enum": ["Warehouse", "Health Facility"] + }, + "Facility Status": { + // "type": "string", + "enum": ["Temporary", "Permanent"] + }, + "Capacity": { + "type": "number", + "minimum": 1, + "maximum": 100000000 + } + }, + "required": [ + "Facility Name", + "Facility Type", + "Facility Status", + "Capacity" + ], + "unique": [ + "Facility Name" + ] + }, + uniqueIdentifier: "id", + uniqueIdentifierColumn: "A", + activeColumn: "G", + activeColumnName: "HCM_ADMIN_CONSOLE_FACILITY_USAGE", + uniqueIdentifierColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", + matchEachKey: true, + parseArrayConfig: { + sheetName: "HCM_ADMIN_CONSOLE_FACILITIES", + parseLogic: [ + { + sheetColumn: "A", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", + resultantPath: "id", + type: "string" + }, + { + sheetColumn: "B", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_NAME", + resultantPath: "name", + type: "string" + }, + { + sheetColumn: "C", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_TYPE", + resultantPath: "usage", + type: "string" + }, + { + sheetColumn: "D", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_STATUS", + resultantPath: "isPermanent", + type: "boolean", + conversionCondition: { + "Permanent": "true", + "Temporary": "" + } + }, + { + sheetColumn: "E", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CAPACITY", + resultantPath: "storageCapacity", + type: "number" + }, + { + sheetColumn: "F", + sheetColumnName: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY" + } + ], + tenantId: { + getValueViaPath: "ResourceDetails.tenantId", + resultantPath: "tenantId" + } + }, + createBulkDetails: { + limit: 50, + createPath: "Facilities", + url: config.host.facilityHost + "facility/v1/bulk/_create" + }, + searchDetails: { + searchElements: [ + { + keyPath: "tenantId", + getValueViaPath: "ResourceDetails.tenantId", + isInParams: true, + isInBody: false, + }, + { + keyPath: "Facility", + isInParams: false, + isInBody: true, + } + ], + searchLimit: { + keyPath: "limit", + value: "200", + isInParams: true, + isInBody: false, + }, + searchOffset: { + keyPath: "offset", + value: "0", + isInParams: true, + isInBody: false, + }, + url: config.host.facilityHost + "facility/v1/_search", + searchPath: "Facilities" + } + }, + "facilityMicroplan": { + requiresToSearchFromSheet: [ + { + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", + searchPath: "Facility.id" + } + ], + boundaryValidation: { + column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY" + }, + sheetSchema: { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "FacilityTemplateSchema", + "type": "object", + "properties": { + "Facility Name": { + "type": "string", + "maxLength": 2000, + "minLength": 1 + }, + "Facility Type": { + // "type": "string", + "enum": ["Warehouse", "Health Facility", "Storing Resource"] + }, + "Facility Status": { + // "type": "string", + "enum": ["Temporary", "Permanent"] + }, + "Capacity": { + "type": "number", + "minimum": 1, + "maximum": 100000000 + } + }, + "required": [ + "Facility Name", + "Facility Type", + "Facility Status", + "Capacity" + ], + "unique": [ + "Facility Name" + ] + }, + uniqueIdentifier: "id", + uniqueIdentifierColumn: "A", + activeColumn: "F", + activeColumnName: "HCM_ADMIN_CONSOLE_FACILITY_USAGE_MICROPLAN", + uniqueIdentifierColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", + matchEachKey: true, + parseArrayConfig: { + sheetName: "HCM_ADMIN_CONSOLE_FACILITIES", + parseLogic: [ + { + sheetColumn: "A", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", + resultantPath: "id", + type: "string" + }, + { + sheetColumn: "B", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_NAME_MICROPLAN", + resultantPath: "name", + type: "string" + }, + { + sheetColumn: "C", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_TYPE_MICROPLAN", + resultantPath: "usage", + type: "string" + }, + { + sheetColumn: "D", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_STATUS_MICROPLAN", + resultantPath: "isPermanent", + type: "boolean", + conversionCondition: { + "Permanent": "true", + "Temporary": "" + } + }, + { + sheetColumn: "E", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CAPACITY_MICROPLAN", + resultantPath: "storageCapacity", + type: "number" + }, + { + sheetColumn: "J", + sheetColumnName: "HCM_ADMIN_CONSOLE_RESIDING_BOUNDARY_CODE_MICROPLAN" + } + ], + tenantId: { + getValueViaPath: "ResourceDetails.tenantId", + resultantPath: "tenantId" + } + }, + createBulkDetails: { + limit: 50, + createPath: "Facilities", + url: config.host.facilityHost + "facility/v1/bulk/_create" + }, + searchDetails: { + searchElements: [ + { + keyPath: "tenantId", + getValueViaPath: "ResourceDetails.tenantId", + isInParams: true, + isInBody: false, + }, + { + keyPath: "Facility", + isInParams: false, + isInBody: true, + } + ], + searchLimit: { + keyPath: "limit", + value: "200", + isInParams: true, + isInBody: false, + }, + searchOffset: { + keyPath: "offset", + value: "0", + isInParams: true, + isInBody: false, + }, + url: config.host.facilityHost + "facility/v1/_search", + searchPath: "Facilities" + } + }, + "boundary": { + parseArrayConfig: { + sheetName: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE", + } + }, + "user": { + boundaryValidation: { + column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY" + }, + sheetSchema: { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "UserTemplateSchema", + "type": "object", + "properties": { + "Name of the Person (Mandatory)": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "Phone Number (Mandatory)": { + "type": "integer", + "minimum": 100000000, + "maximum": 9999999999 + }, + "Role (Mandatory)": { + "type": "string", + "enum": ["Registrar", "Distributor", "Supervisor", "Help Desk", "Monitor Local", "Logistical officer"] + }, + "Employment Type (Mandatory)": { + "enum": ["Temporary", "Permanent"] + } + }, + "required": [ + "Name of the Person (Mandatory)", + "Phone Number (Mandatory)", + "Role (Mandatory)", + "Employment Type (Mandatory)" + ], + "unique": [ + "Phone Number (Mandatory)" + ] + }, + parseArrayConfig: { + sheetName: "HCM_ADMIN_CONSOLE_USER_LIST", + parseLogic: [ + { + sheetColumn: "A", + sheetColumnName: "HCM_ADMIN_CONSOLE_USER_NAME", + resultantPath: "user.name", + type: "string" + }, + { + sheetColumn: "B", + sheetColumnName: "HCM_ADMIN_CONSOLE_USER_PHONE_NUMBER", + resultantPath: "user.mobileNumber", + type: "string" + }, + { + sheetColumn: "C", + sheetColumnName: "HCM_ADMIN_CONSOLE_USER_ROLE", + resultantPath: "user.roles", + type: "string" + }, + { + sheetColumn: "D", + sheetColumnName: "HCM_ADMIN_CONSOLE_USER_EMPLOYMENT_TYPE", + resultantPath: "employeeType", + conversionCondition: { + "Permanent": "PERMANENT", + "Temporary": "TEMPORARY" + } + }, + { + sheetColumn: "E", + sheetColumnName: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY", + resultantPath: "jurisdictions", + type: "string" + } + ], + tenantId: { + getValueViaPath: "ResourceDetails.tenantId", + resultantPath: "tenantId" + } + }, + uniqueIdentifier: "user.userServiceUuid", + uniqueIdentifierColumn: "H", + uniqueIdentifierColumnName: "UserService Uuids", + createBulkDetails: { + limit: 50, + createPath: "Employees", + url: config.host.hrmsHost + config.paths.hrmsEmployeeCreate + }, + searchDetails: { + searchElements: [ + { + keyPath: "tenantId", + getValueViaPath: "ResourceDetails.tenantId", + isInParams: true, + isInBody: false, + } + ], + searchLimit: { + keyPath: "limit", + value: "50", + isInParams: true, + isInBody: false, + }, + searchOffset: { + keyPath: "offset", + value: "0", + isInParams: true, + isInBody: false, + }, + url: config.host.hrmsHost + config.paths.hrmsEmployeeSearch, + searchPath: "Employees" + } + }, + "boundaryWithTarget": { + parseArrayConfig: { + sheetName: "HCM_ADMIN_CONSOLE_BOUNDARY_DATA", + }, + boundaryValidation: { + column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE" + } + } +} + +export default createAndSearch; diff --git a/health-services/project-factory/src/server/config/dbPoolConfig.ts b/health-services/project-factory/src/server/config/dbPoolConfig.ts new file mode 100644 index 00000000000..c5022823846 --- /dev/null +++ b/health-services/project-factory/src/server/config/dbPoolConfig.ts @@ -0,0 +1,15 @@ +import { Pool } from 'pg'; +import config from '.'; + +const pool = new Pool({ + user: config.DB_CONFIG.DB_USER, + host: config.DB_CONFIG.DB_HOST, + database: config.DB_CONFIG.DB_NAME, + password: config.DB_CONFIG.DB_PASSWORD, + port: parseInt(config.DB_CONFIG.DB_PORT), + ssl: { + rejectUnauthorized: false, + }, +}); + +export default pool; \ No newline at end of file diff --git a/health-services/project-factory/src/server/config/error.interface.ts b/health-services/project-factory/src/server/config/error.interface.ts new file mode 100644 index 00000000000..73cabf70404 --- /dev/null +++ b/health-services/project-factory/src/server/config/error.interface.ts @@ -0,0 +1,7 @@ +interface Error { + code: string; + notFound: boolean; + message: string; +} + +export default Error; diff --git a/health-services/project-factory/src/server/config/generateQuery.ts b/health-services/project-factory/src/server/config/generateQuery.ts new file mode 100644 index 00000000000..25bb7f4036e --- /dev/null +++ b/health-services/project-factory/src/server/config/generateQuery.ts @@ -0,0 +1,145 @@ +export const generateQuerySchema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "hierarchyType": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "tenantId": { + "type": "string", + "maxLength": 64, + "minLength": 1 + }, + "campaignName": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "action": { + "type": "string", + "enum": ["create", "draft"], + "maxLength": 64, + "minLength": 1 + }, + "startDate": { + "type": "integer" + }, + "endDate": { + "type": "integer" + }, + "boundaries": { + "type": "array", + "items": { + "type": "object", + "properties": { + "code": { + "type": "string", + "maxLength": 64, + "minLength": 1 + }, + "type": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "isRoot": { + "type": "boolean" + }, + "includeAllChildren": { + "type": "boolean" + } + }, + "required": ["code", "type"] + } + }, + "resources": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filestoreId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "type": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "filename": { + "type": "string", + "maxLength": 128, + "minLength": 1 + } + }, + "required": ["filestoreId", "type"] + } + }, + "projectType": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "deliveryRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "startDate": { + "type": "integer" + }, + "endDate": { + "type": "integer" + }, + "cycleNumber": { + "type": "integer" + }, + "deliveryNumber": { + "type": "integer" + }, + "deliveryRuleNumber": { + "type": "integer" + }, + "products": { + "type": "array", + "items": { + "type": "string", + "maxLength": 128, + "minLength": 1 + } + }, + "conditions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attribute": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "operator": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "value": { + "type": "integer" + } + }, + "required": ["attribute", "operator", "value"] + } + } + }, + "required": ["startDate", "endDate", "cycleNumber", "deliveryNumber", "deliveryRuleNumber", "products", "conditions"] + } + }, + "additionalDetails": { + "type": "object" + } + }, + "required": ["hierarchyType", "tenantId", "campaignName", "action", "startDate", "endDate", "projectType", "deliveryRules", "additionalDetails"] +}; diff --git a/health-services/project-factory/src/server/config/index.ts b/health-services/project-factory/src/server/config/index.ts new file mode 100644 index 00000000000..7260b93c59d --- /dev/null +++ b/health-services/project-factory/src/server/config/index.ts @@ -0,0 +1,169 @@ +// config.js +// Importing necessary module +import { getErrorCodes } from "./constants"; +// Defining the HOST variable +const HOST = process.env.EGOV_HOST || + "https://unified-dev.digit.org/"; +// Checking if HOST is set, if not, exiting the process +if (!HOST) { + console.log("You need to set the HOST variable"); + process.exit(1); +} + + +const getDBSchemaName = (dbSchema = "") => { + return dbSchema ? (dbSchema == "egov" ? "public" : dbSchema) : "public"; +} +// Configuration object containing various environment variables +const config = { + cacheTime : 300, + enableDynamicTemplateFor: process.env.ENABLE_DYNAMIC_TEMPLATE_FOR || "", + isCallGenerateWhenDeliveryConditionsDiffer: (process.env.IS_CALL_GENERATE_WHEN_DELIVERY_CONDITIONS_DIFFER === "true") || false, + prefixForMicroplanCampaigns: "MP", + excludeHierarchyTypeFromBoundaryCodes: (process.env.EXCLUDE_HIERARCHY_TYPE_FROM_BOUNDARY_CODES === "true") || false, + excludeBoundaryNameAtLastFromBoundaryCodes: (process.env.EXCLUDE_BOUNDARY_NAME_AT_LAST_FROM_BOUNDARY_CODES === "true") || false, + masterNameForSchemaOfColumnHeaders: "adminSchema", + masterNameForSplitBoundariesOn: "hierarchyConfig", + boundary: { + boundaryCode: process.env.BOUNDARY_CODE_HEADER_NAME || "HCM_ADMIN_CONSOLE_BOUNDARY_CODE", + boundaryTab: process.env.BOUNDARY_TAB_NAME || "HCM_ADMIN_CONSOLE_BOUNDARY_DATA", + // Default criteria for generating different tabs + generateDifferentTabsOnBasisOf: process.env.SPLIT_BOUNDARIES_ON || "ADMIN_DISTRITO", + // default configurable number of data of boundary type on which generate different tabs + numberOfBoundaryDataOnWhichWeSplit: process.env.SPLIT_BOUNDARIES_ON_LENGTH || "2", + boundaryRelationShipDelay: 3500 + }, + facility: { + facilityTab: process.env.FACILITY_TAB_NAME || "HCM_ADMIN_CONSOLE_FACILITIES", + facilitySchemaMasterName: process.env.FACILITY_SCHEMA_MASTER || "facilitySchema", + }, + user: { + userTab: process.env.USER_TAB_NAME || "HCM_ADMIN_CONSOLE_USER_LIST", + userSchemaMasterName: process.env.USER_SCHEMA_MASTER || "userSchema", + 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, + resetCache: process.env.RESET_CACHE, + redisPort: process.env.REDIS_PORT || "6379", + }, + 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_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", + KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC: process.env.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC || "update-resource-details", + KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC: process.env.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC || "create-resource-activity", + KAFKA_UPDATE_GENERATED_RESOURCE_DETAILS_TOPIC: process.env.KAFKA_UPDATE_GENERATED_RESOURCE_DETAILS_TOPIC || "update-generated-resource-details", + KAFKA_CREATE_GENERATED_RESOURCE_DETAILS_TOPIC: process.env.KAFKA_CREATE_GENERATED_RESOURCE_DETAILS_TOPIC || "create-generated-resource-details", + KAFKA_SAVE_PROCESS_TRACK_TOPIC: process.env.KAFKA_SAVE_PROCESS_TRACK_TOPIC || "save-process-track", + KAFKA_UPDATE_PROCESS_TRACK_TOPIC: process.env.KAFKA_UPDATE_PROCESS_TRACK_TOPIC || "update-process-track", + KAFKA_TEST_TOPIC: "test-topic-project-factory", + }, + + // Database configuration + DB_CONFIG: { + DB_USER: process.env.DB_USER || "postgres", + DB_HOST: process.env.DB_HOST?.split(':')[0] || "localhost", + DB_NAME: process.env.DB_NAME || "postgres", + DB_PASSWORD: process.env.DB_PASSWORD || "postgres", + DB_PORT: process.env.DB_PORT || "5432", + DB_CAMPAIGN_DETAILS_TABLE_NAME: `${getDBSchemaName(process.env.DB_SCHEMA)}.eg_cm_campaign_details`, + DB_CAMPAIGN_PROCESS_TABLE_NAME: `${getDBSchemaName(process.env.DB_SCHEMA)}.eg_cm_campaign_process`, + DB_GENERATED_RESOURCE_DETAILS_TABLE_NAME: `${getDBSchemaName(process.env.DB_SCHEMA)}.eg_cm_generated_resource_details`, + DB_RESOURCE_DETAILS_TABLE_NAME: `${getDBSchemaName(process.env.DB_SCHEMA)}.eg_cm_resource_details` + }, + // Application configuration + app: { + port: parseInt(process.env.APP_PORT || "8080") || 8080, + host: HOST, + contextPath: process.env.CONTEXT_PATH || "/project-factory", + logLevel: process.env.APP_LOG_LEVEL || "debug", + debugLogCharLimit: process.env.APP_MAX_DEBUG_CHAR ? Number(process.env.APP_MAX_DEBUG_CHAR) : 1000 + }, + localisation: { + defaultLocale: process.env.LOCALE || "en_MZ", + boundaryPrefix: "rainmaker-boundary", + localizationModule: process.env.LOCALIZATION_MODULE || "rainmaker-hcm-admin-schemas", + }, + // targetColumnsForSpecificCampaigns: { + // bedNetCampaignColumns: ["HCM_ADMIN_CONSOLE_TARGET"], + // smcCampaignColumns: ["HCM_ADMIN_CONSOLE_TARGET_SMC_AGE_3_TO_11", "HCM_ADMIN_CONSOLE_TARGET_SMC_AGE_12_TO_59"] + // }, + // Host configuration + host: { + serverHost: HOST, + // Kafka broker host + KAFKA_BROKER_HOST: process.env.KAFKA_BROKER_HOST || "kafka-v2.kafka-cluster:9092", + redisHost: process.env.REDIS_HOST || "localhost", + mdms: process.env.EGOV_MDMS_HOST || "https://unified-dev.digit.org/", + mdmsV2: process.env.EGOV_MDMS_V2_HOST || "https://unified-dev.digit.org/", + filestore: process.env.EGOV_FILESTORE_SERVICE_HOST || "https://unified-dev.digit.org/", + projectFactoryBff: "http://localhost:8080/", + idGenHost: process.env.EGOV_IDGEN_HOST || "https://unified-dev.digit.org/", + facilityHost: process.env.EGOV_FACILITY_HOST || "https://unified-dev.digit.org/", + boundaryHost: process.env.EGOV_BOUNDARY_HOST || "https://unified-dev.digit.org/", + projectHost: process.env.EGOV_PROJECT_HOST || "https://unified-dev.digit.org/", + userHost: process.env.EGOV_USER_HOST || "https://unified-dev.digit.org/", + productHost: process.env.EGOV_PRODUCT_HOST || "https://unified-dev.digit.org/", + hrmsHost: process.env.EGOV_HRMS_HOST || "https://unified-dev.digit.org/", + localizationHost: process.env.EGOV_LOCALIZATION_HOST || "https://unified-dev.digit.org/", + healthIndividualHost: process.env.EGOV_HEALTH_INDIVIDUAL_HOST || "https://unified-dev.digit.org/", + }, + // Paths for different services + paths: { + filestore: process.env.FILE_STORE_SERVICE_END_POINT || "filestore/v1/files", + mdms_search: process.env.EGOV_MDMS_SEARCH_ENDPOINT || "egov-mdms-service/v2/_search", + mdms_v1_search: process.env.EGOV_MDMS_V1_SEARCH_ENDPOINT || "egov-mdms-service/v1/_search", + idGen: process.env.EGOV_IDGEN_PATH || "egov-idgen/id/_generate", + mdmsSchema: process.env.EGOV_MDMS_SCHEMA_PATH || "egov-mdms-service/schema/v1/_search", + boundaryRelationship: process.env.EGOV_BOUNDARY_RELATIONSHIP_SEARCHPATH || "boundary-service/boundary-relationships/_search", + boundaryServiceSearch: process.env.EGOV_BOUNDARY_SERVICE_SEARCHPATH || "boundary-service/boundary/_search", + boundaryHierarchy: process.env.EGOV_BOUNDARY_HIERARCHY_SEARCHPATH || "boundary-service/boundary-hierarchy-definition/_search", + projectCreate: process.env.HEALTH_PROJECT_CREATE_PATH || "health-project/v1/_create", + projectUpdate: process.env.HEALTH_PROJECT_UPDATE_PATH || "health-project/v1/_update", + projectSearch: process.env.HEALTH_PROJECT_SEARCH_PATH || "health-project/v1/_search", + staffCreate: process.env.EGOV_PROJECT_STAFF_CREATE_PATH || "health-project/staff/v1/_create", + projectResourceCreate: process.env.EGOV_PROJECT_RESOURCE_CREATE_PATH || "health-project/resource/v1/_create", + projectFacilityCreate: process.env.EGOV_PROJECT_RESOURCE_FACILITY_PATH || "health-project/facility/v1/_create", + userSearch: process.env.EGOV_USER_SEARCH_PATH || "user/_search", + facilitySearch: process.env.EGOV_FACILITY_SEARCH_PATH || "facility/v1/_search", + productVariantSearch: process.env.EGOV_PRODUCT_VARIANT_SEARCH_PATH || "product/variant/v1/_search", + boundaryEntity: process.env.EGOV_BOUNDARY_ENTITY_SEARCHPATH || "boundary-service/boundary/_search", + facilityBulkCreate: process.env.EGOV_FACILITY_BULK_CREATE || "facility/v1/bulk/_create", + hrmsEmployeeCreate: process.env.EGOV_HRMS_EMPLOYEE_CREATE_PATH || "health-hrms/employees/_create", + hrmsEmployeeSearch: process.env.EGOV_HRMS_EMPLOYEE_SEARCH_PATH || "health-hrms/employees/_search", + localizationSearch: process.env.EGOV_LOCALIZATION_SEARCH || "localization/messages/v1/_search", + localizationCreate: "localization/messages/v1/_upsert", + projectTypeSearch: "project-factory/v1/project-type/search", + boundaryRelationshipCreate: "boundary-service/boundary-relationships/_create", + mdmsV2SchemaSearch: "mdms-v2/schema/v1/_search", + mdms_v2_search: "mdms-v2/v2/_search", + healthIndividualSearch: process.env.EGOV_HEALTH_INDIVIDUAL_SEARCH || "health-individual/v1/_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", + userMainBoundary: "mz", + userMainBoundaryType: "Country", + idgen: { + format: process.env.CMP_IDGEN_FORMAT || "CMP-[cy:yyyy-MM-dd]-[SEQ_EG_CMP_ID]", + idName: process.env.CMP_IDGEN_IDNAME || "campaign.number" + }, + matchFacilityData: false, + retryCount: process.env.CREATE_RESOURCE_RETRY_COUNT || "3", + notCreateUserIfAlreadyThere: process.env.NOT_CREATE_USER_IF_ALREADY_THERE || false, + maxHttpRetries: process.env.MAX_HTTP_RETRIES || "4" + } +}; +// Exporting getErrorCodes function and config object +export { getErrorCodes }; +export default config; diff --git a/health-services/project-factory/src/server/config/models/SearchCriteria.ts b/health-services/project-factory/src/server/config/models/SearchCriteria.ts new file mode 100644 index 00000000000..54d30a7d0e1 --- /dev/null +++ b/health-services/project-factory/src/server/config/models/SearchCriteria.ts @@ -0,0 +1,26 @@ +export const searchCriteriaSchema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "id": { + "type": "array", + "items": { + "type": "string" + } + }, + "tenantId": { + "type": "string", + "minLength": 1 + }, + "type": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": ["tenantId"], + "additionalProperties": false +} + + diff --git a/health-services/project-factory/src/server/config/models/campaignDetails.ts b/health-services/project-factory/src/server/config/models/campaignDetails.ts new file mode 100644 index 00000000000..e5c1aef4ed7 --- /dev/null +++ b/health-services/project-factory/src/server/config/models/campaignDetails.ts @@ -0,0 +1,102 @@ +export const campaignDetailsSchema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "hierarchyType": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "tenantId": { + "type": "string", + "maxLength": 64, + "minLength": 1 + }, + "campaignName": { + "type": "string", + "maxLength": 250, + "minLength": 2 + }, + "action": { + "type": "string", + "enum": ["create", "draft", "changeDates"], + "maxLength": 64, + "minLength": 1 + }, + "startDate": { + "type": "integer" + }, + "endDate": { + "type": "integer" + }, + "boundaries": { + "type": "array", + "items": { + "type": "object", + "properties": { + "code": { + "type": "string", + "maxLength": 64, + "minLength": 1 + }, + "type": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "isRoot": { + "type": "boolean" + }, + "includeAllChildren": { + "type": "boolean" + } + }, + "required": ["code", "type"] + } + }, + "resources": { + "type": "array", + "maxItems": 3, + "items": { + "type": "object", + "properties": { + "filestoreId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "type": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "filename": { + "type": "string", + "maxLength": 128, + "minLength": 1, + "pattern": "^.+\\.(xlsx|xls)$" + }, + "resourceId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + } + }, + "required": ["filestoreId", "type", "filename", "resourceId"] + } + }, + "projectType": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "deliveryRules": { + "type": "array", + "minItems": 1 + }, + "additionalDetails": { + "type": "object" + } + }, + "required": ["hierarchyType", "tenantId", "campaignName", "action", "startDate", "endDate", "projectType", "deliveryRules", "additionalDetails"] +}; diff --git a/health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts b/health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts new file mode 100644 index 00000000000..873d2b5d034 --- /dev/null +++ b/health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts @@ -0,0 +1,98 @@ +export const campaignDetailsDraftSchema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "hierarchyType": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "tenantId": { + "type": "string", + "maxLength": 64, + "minLength": 1 + }, + "campaignName": { + "type": "string", + "maxLength": 250, + "minLength": 2 + }, + "action": { + "type": "string", + "enum": ["create", "draft"], + "maxLength": 64, + "minLength": 1 + }, + "startDate": { + "type": "integer" + }, + "endDate": { + "type": "integer" + }, + "boundaries": { + "type": "array", + "items": { + "type": "object", + "properties": { + "code": { + "type": "string", + "maxLength": 64, + "minLength": 1 + }, + "type": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "isRoot": { + "type": "boolean" + }, + "includeAllChildren": { + "type": "boolean" + } + } + } + }, + "resources": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filestoreId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "type": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "filename": { + "type": "string", + "maxLength": 128, + "minLength": 1, + "pattern": "^.+\\.(xlsx|xls)$" + }, + "resourceId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + } + }, + } + }, + "projectType": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "deliveryRules": { + "type": "array" + }, + "additionalDetails": { + "type": "object" + } + }, + "required": ["tenantId", "campaignName", "hierarchyType"] +}; diff --git a/health-services/project-factory/src/server/config/models/createRequestSchema.ts b/health-services/project-factory/src/server/config/models/createRequestSchema.ts new file mode 100644 index 00000000000..18a96101fbd --- /dev/null +++ b/health-services/project-factory/src/server/config/models/createRequestSchema.ts @@ -0,0 +1,39 @@ +export const createRequestSchema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["boundary", "facility", "user", "boundaryWithTarget","facilityMicroplan"] + }, + "tenantId": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "fileStoreId": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "action": { + "type": "string", + "enum": ["create", "validate"] + }, + "hierarchyType": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "campaignId": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "additionalDetails": { + "type": "object" + } + }, + "required": ["type", "tenantId", "fileStoreId", "action", "hierarchyType"], + "additionalProperties": false +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts b/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts new file mode 100644 index 00000000000..d23b7df2f4f --- /dev/null +++ b/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts @@ -0,0 +1,45 @@ +export const downloadRequestSchema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "type": { + "type": "string", + "maxLength": 128, + "minLength": 1, + "enum": [ + "facility", + "user", + "boundary", + "facilityWithBoundary", + "userWithBoundary" + ] + }, + "hierarchyType": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "id": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "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 diff --git a/health-services/project-factory/src/server/config/models/generateRequestSchema.ts b/health-services/project-factory/src/server/config/models/generateRequestSchema.ts new file mode 100644 index 00000000000..4ca530f9393 --- /dev/null +++ b/health-services/project-factory/src/server/config/models/generateRequestSchema.ts @@ -0,0 +1,35 @@ +export const generateRequestSchema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "maxLength": 128, + "minLength": 1, + }, + "type": { + "type": "string", + "maxLength": 128, + "minLength": 1, + "enum": [ + "boundary", + "facilityWithBoundary", + "userWithBoundary" + ] + }, + "hierarchyType": { + "type": "string", + "maxLength": 128, + "minLength": 1, + }, + "forceUpdate": { + "type": "string", + "enum": ["true", "false"] + }, + "campaignId": { + "type": "string" + } + }, + "required": ["tenantId", "type", "hierarchyType", "campaignId"], + "additionalProperties": false +} diff --git a/health-services/project-factory/src/server/config/models/searchCampaignDetails.ts b/health-services/project-factory/src/server/config/models/searchCampaignDetails.ts new file mode 100644 index 00000000000..155e8babbc4 --- /dev/null +++ b/health-services/project-factory/src/server/config/models/searchCampaignDetails.ts @@ -0,0 +1,74 @@ +export const searchCampaignDetailsSchema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "ids": { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + }, + "tenantId": { + "type": "string", + "minLength": 1 + }, + "startDate": { + "type": "integer", + "minimum": 0 + }, + "endDate": { + "type": "integer", + "minimum": 0 + }, + "campaignsIncludeDates": { + "type": "boolean" + }, + "projectType": { + "type": "string" + }, + "campaignName": { + "type": "string", + "minLength": 1 + }, + "status": { + "oneOf": [ + { "type": "string" }, + { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + } + ] + }, + "createdBy": { + "type": "string" + }, + "campaignNumber": { + "type": "string" + }, + "pagination": { + "type": "object", + "properties": { + "sortBy": { + "type": "string" + }, + "sortOrder": { + "type": "string", + "enum": ["asc", "desc"] + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 100 + }, + "offset": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "required": ["tenantId"], + "additionalProperties": false +} diff --git a/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts b/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts new file mode 100644 index 00000000000..dc3232294e2 --- /dev/null +++ b/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts @@ -0,0 +1,137 @@ +import * as express from "express"; +import { createCampaignService, createProjectTypeCampaignService, searchProcessTracksService, searchProjectTypeCampaignService, updateProjectTypeCampaignService } from "../../service/campaignManageService"; +import { logger } from "../../utils/logger"; +import { errorResponder, sendResponse } from "../../utils/genericUtils"; + + + +// Define the MeasurementController class +class campaignManageController { + // Define class properties + public path = "/v1/project-type"; + public router = express.Router(); + public dayInMilliSecond = 86400000; + + // Constructor to initialize routes + constructor() { + this.intializeRoutes(); + } + + // Initialize routes for MeasurementController + public intializeRoutes() { + this.router.post(`${this.path}/create`, this.createProjectTypeCampaign); + this.router.post(`${this.path}/update`, this.updateProjectTypeCampaign); + this.router.post(`${this.path}/search`, this.searchProjectTypeCampaign); + this.router.post(`${this.path}/createCampaign`, this.createCampaign); + this.router.post(`${this.path}/getProcessTrack`, this.searchProcessTracks); + } + /** + * Handles the creation of a project type campaign. + * @param request The Express request object. + * @param response The Express response object. + */ + createProjectTypeCampaign = async ( + request: express.Request, + response: express.Response + ) => { + try { + logger.info("RECEIVED A PROJECT TYPE CREATE REQUEST"); + const CampaignDetails = await createProjectTypeCampaignService(request); + return sendResponse(response, { CampaignDetails }, request); + } catch (e: any) { + console.log(e) + logger.error(String(e)) + // Handle errors and send error response + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + }; + + /** + * Handles the update of a project type campaign. + * @param request The Express request object. + * @param response The Express response object. + */ + updateProjectTypeCampaign = async ( + request: express.Request, + response: express.Response + ) => { + try { + logger.info("RECEIVED A PROJECT TYPE UPDATE REQUEST"); + const CampaignDetails = await updateProjectTypeCampaignService(request); + return sendResponse(response, { CampaignDetails }, request); + } catch (e: any) { + console.log(e) + logger.error(String(e)) + // Handle errors and send error response + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + }; + + /** + * Handles the search for project type campaigns. + * @param request The Express request object. + * @param response The Express response object. + */ + searchProjectTypeCampaign = async ( + request: express.Request, + response: express.Response + ) => { + try { + logger.info("RECEIVED A PROJECT TYPE SEARCH REQUEST"); + const responseBody = await searchProjectTypeCampaignService(request); + // Send response with campaign details and total count + return sendResponse(response, responseBody, request); + } catch (e: any) { + console.log(e) + logger.error(String(e)) + // Handle errors and send error response + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + }; + + /** + * Handles the creation of a campaign. + * @param request The Express request object. + * @param response The Express response object. + */ + createCampaign = async ( + request: express.Request, + response: express.Response + ) => { + try { + logger.info("RECEIVED A CAMPAIGN CREATE REQUEST"); + const Campaign = await createCampaignService(request?.body); + // Send response with campaign details + return sendResponse(response, { Campaign }, request); + } + catch (e: any) { + console.log(e) + logger.error(String(e)) + // Handle errors and send error response + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + }; + + searchProcessTracks = async ( + request: express.Request, + response: express.Response + ) => { + try { + logger.info("RECEIVED A PROCESS SEARCH REQUEST"); + const processTrack = await searchProcessTracksService(request); + // Send response with campaign details + return sendResponse(response, { processTrack }, request); + } + catch (e: any) { + console.log(e) + logger.error(String(e)) + // Handle errors and send error response + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + }; + +}; +export default campaignManageController; + + + diff --git a/health-services/project-factory/src/server/controllers/dataManage/dataManage.controller.ts b/health-services/project-factory/src/server/controllers/dataManage/dataManage.controller.ts new file mode 100644 index 00000000000..1ad8b70ae6e --- /dev/null +++ b/health-services/project-factory/src/server/controllers/dataManage/dataManage.controller.ts @@ -0,0 +1,107 @@ +import * as express from "express"; +import { createDataService, downloadDataService, generateDataService, searchDataService } from "../../service/dataManageService"; +import { errorResponder, sendResponse } from "../../utils/genericUtils"; +import { logger } from "../../utils/logger"; + + + + + + + +// Define the MeasurementController class +class dataManageController { + // Define class properties + public path = "/v1/data"; + public router = express.Router(); + public dayInMilliSecond = 86400000; + + // Constructor to initialize routes + constructor() { + this.intializeRoutes(); + } + + // Initialize routes for MeasurementController + public intializeRoutes() { + this.router.post(`${this.path}/_generate`, this.generateData); + this.router.post(`${this.path}/_download`, this.downloadData) + this.router.post(`${this.path}/_create`, this.createData); + this.router.post(`${this.path}/_search`, this.searchData); + } + /** +* Generates data based on the request and sends the response. +* @param request The Express request object. +* @param response The Express response object. +*/ + generateData = async (request: express.Request, response: express.Response) => { + try { + logger.info(`RECEIVED A DATA GENERATE REQUEST FOR TYPE :: ${request?.query?.type}`); + const GeneratedResource = await generateDataService(request); + return sendResponse(response, { GeneratedResource }, request); + } catch (e: any) { + console.log(e) + logger.error(String(e)) + // Handle errors and send error response + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + }; + + /** + * Downloads data based on the request and sends the response. + * @param request The Express request object. + * @param response The Express response object. + */ + downloadData = async (request: express.Request, response: express.Response) => { + try { + logger.info(`RECEIVED A DATA DOWNLOAD REQUEST FOR TYPE :: ${request?.query?.type}`); + const GeneratedResource = await downloadDataService(request); + return sendResponse(response, { GeneratedResource }, request); + } catch (e: any) { + console.log(e) + logger.error(String(e)); + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + } + + /** + * Creates data based on the request and sends the response. + * @param request The Express request object. + * @param response The Express response object. + */ + createData = async (request: any, response: any) => { + try { + logger.info(`RECEIVED A DATA CREATE REQUEST FOR TYPE :: ${request?.body?.ResourceDetails?.type}`); + const ResourceDetails = await createDataService(request); + // Send response with resource details + return sendResponse(response, { ResourceDetails }, request); + } catch (e: any) { + console.log(e) + logger.error(String(e)) + // Handle errors and send error response + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + } + + /** + * Searches for data based on the request and sends the response. + * @param request The Express request object. + * @param response The Express response object. + */ + searchData = async (request: any, response: any) => { + try { + logger.info(`RECEIVED A DATA SEARCH REQUEST FOR TYPE :: ${request?.body?.SearchCriteria?.type}`); + const ResourceDetails = await searchDataService(request) + return sendResponse(response, { ResourceDetails }, request); + } catch (e: any) { + console.log(e) + logger.error(String(e)) + // Handle errors and send error response + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + } + +}; +export default dataManageController; + + + diff --git a/health-services/project-factory/src/server/controllers/index.ts b/health-services/project-factory/src/server/controllers/index.ts new file mode 100644 index 00000000000..85e544ed9be --- /dev/null +++ b/health-services/project-factory/src/server/controllers/index.ts @@ -0,0 +1,12 @@ +import { listener } from "../kafka/Listener"; +import campaignManageController from "./campaignManage/campaignManage.controller"; +import dataManageController from "./dataManage/dataManage.controller"; + +listener(); + +const controllers = [ + new campaignManageController(), + new dataManageController() +] + +export default controllers; \ No newline at end of file diff --git a/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts b/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts new file mode 100644 index 00000000000..3591c1c016c --- /dev/null +++ b/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts @@ -0,0 +1,118 @@ +import * as express from "express"; +import { logger } from "../../utils/logger"; +import { httpRequest } from "../../utils/request"; +import config from "../../config/index"; +import { convertLocalisationResponseToMap } from "../../utils/localisationUtils"; + +let cachedResponse = {}; + +class Localisation { + public path = "/localization/messages/v1"; + public router = express.Router(); + public dayInMilliSecond = 86400000; + private cachedResponse: any = {}; // Property to store the cached response + private localizationHost; + // Hold the single instance of the class + private static instance: Localisation; + constructor() { + this.localizationHost = config.host.localizationHost + } + // Public method to provide access to the single instance + public static getInstance(): Localisation { + if (!Localisation.instance) { + Localisation.instance = new Localisation(); + } + return Localisation.instance; + } + + // private getLocalisationMap = (): any => { + // //{ + // return Object.values(this.cachedResponse).reduce((acc: any, curr: any) => { + // acc = { ...acc, ...curr }; + // return acc; + // }, {}); // + // }; + // search localization + public getLocalisedData: any = async ( + module: string, + locale: string, + tenantId: string + ) => { + logger.info( + `Checks Localisation message is available in cache for module ${module}, locale ${locale}, tenantId ${tenantId}` + ); + if (!this?.cachedResponse?.[`${module}-${locale}`]) { + logger.info(`Not found in cache`); + await this.fetchLocalisationMessage(module, locale, tenantId); + } + logger.info(`Found in cache`); + return this?.cachedResponse?.[`${module}-${locale}`]; + }; + // fetch localization messages + private fetchLocalisationMessage = async ( + module: string, + locale: string, + tenantId: string + ) => { + logger.info( + `Received Localisation fetch for module ${module}, locale ${locale}, tenantId ${tenantId}` + ); + const params = { + tenantId, + locale, + module, + }; + const url = this.localizationHost + config.paths.localizationSearch; + const localisationResponse = await httpRequest(url, {}, params); + logger.info( + `Fetched Localisation Message for module ${module}, locale ${locale}, tenantId ${tenantId} with count ${localisationResponse?.messages?.length}` + ); + this.cachedResponse = { + ...cachedResponse, + ...this.cachedResponse, + [`${module}-${locale}`]: { + ...convertLocalisationResponseToMap(localisationResponse?.messages), + }, + }; + logger.info( + `Cached Localisation Message, now available modules in cache are : ${JSON.stringify( + Object.keys(this.cachedResponse) + )}` + ); + cachedResponse = { ...this.cachedResponse }; + }; + + /** + * Create localisation entries by sending a POST request to the localization host. + * @param messages - Array of localisation messages to be created. + * @param request - Request object containing necessary information. + */ + public createLocalisation = async ( + messages: any[] = [], + tenantId: string, + request: any = {} + ) => { + try { + // Extract RequestInfo from request body + const { RequestInfo } = request.body; + // Construct request body with RequestInfo and localisation messages + const requestBody = { RequestInfo, messages, tenantId }; + // Construct URL for localization create endpoint + const url = + this.localizationHost + config.paths.localizationCreate; + // Log the start of the localisation messages creation process + logger.info("Creating the localisation messages"); + // Send HTTP POST request to create localisation messages + + await httpRequest(url, requestBody); + // Log the completion of the localisation messages creation process + logger.info("Localisation messages created successfully"); + } catch (e: any) { + // Log and handle any errors that occur during the process + console.log(e); + logger.error(String(e)); + } + }; +} + +export default Localisation; diff --git a/health-services/project-factory/src/server/index.ts b/health-services/project-factory/src/server/index.ts new file mode 100644 index 00000000000..0278a389aaa --- /dev/null +++ b/health-services/project-factory/src/server/index.ts @@ -0,0 +1,10 @@ +import App from './app'; +import controllers from './controllers'; +import config from "./config"; + +const app = new App( + controllers, + config.app.port, +); + +app.listen(); diff --git a/health-services/project-factory/src/server/kafka/Listener.ts b/health-services/project-factory/src/server/kafka/Listener.ts new file mode 100644 index 00000000000..128f99c08cb --- /dev/null +++ b/health-services/project-factory/src/server/kafka/Listener.ts @@ -0,0 +1,55 @@ +import { ConsumerGroup, ConsumerGroupOptions, Message } from 'kafka-node'; +import config from '../config'; +import { getFormattedStringForDebug, logger } from '../utils/logger'; +import { shutdownGracefully } from '../utils/genericUtils'; +import { handleCampaignMapping } from '../utils/campaignMappingUtils'; + +// Kafka Configuration +const kafkaConfig: ConsumerGroupOptions = { + kafkaHost: config?.host?.KAFKA_BROKER_HOST, + groupId: 'project-factory', + autoCommit: true, + autoCommitIntervalMs: 5000, + fromOffset: 'latest', +}; + +// Topic Names +const topicNames = [ + config.kafka.KAFKA_START_CAMPAIGN_MAPPING_TOPIC, + config.kafka.KAFKA_TEST_TOPIC +]; + +// Consumer Group Initialization +const consumerGroup = new ConsumerGroup(kafkaConfig, topicNames); + +// Kafka Listener +export function listener() { + consumerGroup.on('message', async (message: Message) => { + try { + 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 from topic ${message.topic}`); + logger.debug(`KAFKA :: LISTENER :: Message: ${getFormattedStringForDebug(messageObject)}`); + } catch (error) { + logger.error(`KAFKA :: LISTENER :: Error processing message: ${error}`); + console.error(error); + } + }); + + consumerGroup.on('error', (err) => { + logger.error(`Consumer Error: ${err}`); + shutdownGracefully(); + }); + + consumerGroup.on('offsetOutOfRange', (err) => { + logger.error(`Offset out of range error: ${err}`); + }); +} diff --git a/health-services/project-factory/src/server/kafka/Producer.ts b/health-services/project-factory/src/server/kafka/Producer.ts new file mode 100644 index 00000000000..dc19acc2fa1 --- /dev/null +++ b/health-services/project-factory/src/server/kafka/Producer.ts @@ -0,0 +1,111 @@ +import { Producer, KafkaClient } from 'kafka-node'; +import { 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 sendWithRetries = (payloads: any[], retries = 3, shutdown: boolean = false): Promise => { + return new Promise((resolve, reject) => { + producer.send(payloads, async (err: any) => { + if (err) { + logger.error('Error sending message:', err); + logger.debug(`Was trying to send: ${JSON.stringify(payloads)}`); + if (retries > 0) { + logger.info(`Retrying to send message. Retries left: ${retries}`); + await new Promise(resolve => setTimeout(resolve, 2000)); // wait before retrying + resolve(sendWithRetries(payloads, retries - 1, shutdown)); + } else { + // Attempt to reconnect and retry + logger.error('Failed to send message after retries. Reconnecting producer...'); + if (shutdown) { + shutdownGracefully(); + } + else { + producer.close(() => { + createKafkaClientAndProducer(); + setTimeout(() => { + sendWithRetries(payloads, 1, true).catch(reject); + }, 2000); // wait before retrying after reconnect + }); + } + } + } else { + logger.info('Message sent successfully'); + resolve(); + } + }); + }); +}; + +async function produceModifiedMessages(modifiedMessages: any[], topic: any) { + try { + logger.info(`KAFKA :: PRODUCER :: A message sent to topic ${topic}`); + logger.debug(`KAFKA :: PRODUCER :: Message ${JSON.stringify(modifiedMessages)}`); + const payloads = [ + { + topic: topic, + messages: JSON.stringify(modifiedMessages), + }, + ]; + + await sendWithRetries(payloads, 3); + } catch (error) { + logger.error(`KAFKA :: PRODUCER :: Exception caught: ${JSON.stringify(error)}`); + throwError("COMMON", 400, "KAFKA_ERROR", "Some error occurred in Kafka"); // Re-throw the error after logging it + } +} + +export { produceModifiedMessages }; diff --git a/health-services/project-factory/src/server/service/campaignManageService.ts b/health-services/project-factory/src/server/service/campaignManageService.ts new file mode 100644 index 00000000000..4b397e8b28f --- /dev/null +++ b/health-services/project-factory/src/server/service/campaignManageService.ts @@ -0,0 +1,79 @@ +import express from "express"; +import { processBasedOnAction, searchProjectCampaignResourcData } from "../utils/campaignUtils"; +import { logger } from "../utils/logger"; +import { validateProjectCampaignRequest, validateSearchProcessTracksRequest, validateSearchProjectCampaignRequest } from "../validators/campaignValidators"; +import { validateCampaignRequest } from "../validators/genericValidator"; +import { createRelatedResouce } from "../api/genericApis"; +import { enrichCampaign } from "../api/campaignApis"; +import { getProcessDetails, modifyProcessDetails } from "../utils/processTrackUtils"; + +async function createProjectTypeCampaignService(request: express.Request) { + // Validate the request for creating a project type campaign + await validateProjectCampaignRequest(request, "create"); + logger.info("VALIDATED THE PROJECT TYPE CREATE REQUEST"); + + // Process the action based on the request type + await processBasedOnAction(request, "create"); + return request?.body?.CampaignDetails; +} + +async function updateProjectTypeCampaignService(request: express.Request) { + + await validateProjectCampaignRequest(request, "update"); + logger.info("VALIDATED THE PROJECT TYPE UPDATE REQUEST"); + + // Process the action based on the request type + await processBasedOnAction(request, "update"); + return request?.body?.CampaignDetails; +} + +async function searchProjectTypeCampaignService( + request: express.Request, +) { + // Validate the search request for project type campaigns + await validateSearchProjectCampaignRequest(request); + logger.info("VALIDATED THE PROJECT TYPE SEARCH REQUEST"); + + // Search for project campaign resource data + await searchProjectCampaignResourcData(request); + const responseBody: any = { CampaignDetails: request?.body?.CampaignDetails, totalCount: request?.body?.totalCount } + return responseBody; +}; + +async function createCampaignService( + requestBody: any +) { + await validateCampaignRequest(requestBody) + logger.info("VALIDATED THE CAMPAIGN CREATE REQUEST"); + + // Create related resource + await createRelatedResouce(requestBody) + + // Enrich the campaign + await enrichCampaign(requestBody) + return requestBody?.Campaign +}; + +async function searchProcessTracksService( + request: express.Request +) { + await validateSearchProcessTracksRequest(request) + logger.info("VALIDATED THE PROCESS SEARCH REQUEST"); + + // Search and return related process tracks + const processDetailsArray = await getProcessDetails(request?.query?.campaignId as string) + + // sort and modify process details so that details with status as toBeCompleted comes in last + const resultArray = modifyProcessDetails(processDetailsArray) + + return resultArray +}; + + +export { + createProjectTypeCampaignService, + updateProjectTypeCampaignService, + searchProjectTypeCampaignService, + createCampaignService, + searchProcessTracksService +} diff --git a/health-services/project-factory/src/server/service/dataManageService.ts b/health-services/project-factory/src/server/service/dataManageService.ts new file mode 100644 index 00000000000..f6ad7105f65 --- /dev/null +++ b/health-services/project-factory/src/server/service/dataManageService.ts @@ -0,0 +1,125 @@ +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 { getFormattedStringForDebug, logger } from "../utils/logger"; +import { validateCreateRequest, validateDownloadRequest, validateSearchRequest } from "../validators/campaignValidators"; +import { validateGenerateRequest } from "../validators/genericValidator"; +import { getLocalisationModuleName } from "../utils/localisationUtils"; +import { getBoundaryTabName } from "../utils/boundaryUtils"; +import { getNewExcelWorkbook } from "../utils/excelUtils"; +import { redis, checkRedisConnection } from "../utils/redisUtils"; // Importing checkRedisConnection function +import config from '../config/index' + + + +const generateDataService = async (request: express.Request) => { + // Validate the generate request + await validateGenerateRequest(request); + logger.info("VALIDATED THE DATA GENERATE REQUEST"); + await processGenerate(request); + // Send response with generated resource details + return request?.body?.generatedResource; +}; + + +const downloadDataService = async (request: express.Request) => { + await validateDownloadRequest(request); + logger.info("VALIDATED THE DATA DOWNLOAD REQUEST"); + + const type = request.query.type; + // Get response data from the database + const responseData = await searchGeneratedResources(request); + // Check if response data is available + if (!responseData || responseData.length === 0 && !request?.query?.id) { + logger.error("No data of type " + type + " with status Completed or with given id presnt in db ") + // Throw error if data is not found + throwError("CAMPAIGN", 500, "GENERATION_REQUIRE"); + } + return responseData; +} + +const getBoundaryDataService = async ( + request: express.Request, 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 localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler(request, request?.query?.tenantId, getLocalisationModuleName(hierarchyType)); + const localizationMapModule = await getLocalizedMessagesHandler(request, request?.query?.tenantId); + const localizationMap = { ...localizationMapHierarchy, ...localizationMapModule }; + // Retrieve boundary sheet data + const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); + const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap); + const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); + addDataToSheet(boundarySheet, boundarySheetData); + const boundaryFileDetails: any = await createAndUploadFile(workbook, request); + // Return boundary file details + logger.info("RETURNS THE BOUNDARY RESPONSE"); + 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); + } +}; + + +const createDataService = async (request: any) => { + + const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId); + // Validate the create request + logger.info("Validating data create request") + await validateCreateRequest(request, localizationMap); + logger.info("VALIDATED THE DATA CREATE REQUEST"); + + // Enrich resource details + await enrichResourceDetails(request); + + // Process the generic request + await processGenericRequest(request, localizationMap); + return request?.body?.ResourceDetails; +} + +const searchDataService = async (request: any) => { + // Validate the search request + await validateSearchRequest(request); + logger.info("VALIDATED THE DATA GENERATE REQUEST"); + // Process the data search request + await processDataSearchRequest(request); + // Send response with resource details + return request?.body?.ResourceDetails; +} + +export { + generateDataService, + downloadDataService, + getBoundaryDataService, + createDataService, + searchDataService +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/tracing.ts b/health-services/project-factory/src/server/tracing.ts new file mode 100644 index 00000000000..34a162de7d8 --- /dev/null +++ b/health-services/project-factory/src/server/tracing.ts @@ -0,0 +1,45 @@ +import { initTracer } from 'jaeger-client'; +import { FORMAT_HTTP_HEADERS, Tags } from 'opentracing'; + +// Initialize Jaeger Tracer +const config = { + serviceName: 'my-express-service', + sampler: { + type: 'const', + param: 1, + }, + reporter: { + logSpans: true, + collectorEndpoint: 'http://localhost:14268/api/traces', // Ensure this URL is correct + }, +}; + +const options = { + tags: { + 'my-express-service.version': '1.0.0', + }, +}; + +const tracer = initTracer(config, options); + +export const tracingMiddleware = (req: any, res: any, next: any) => { + const parentSpanContext = tracer.extract(FORMAT_HTTP_HEADERS, req.headers); + + // Conditionally create span based on parentSpanContext + const span = parentSpanContext ? + tracer.startSpan(req.path, { childOf: parentSpanContext }) : + tracer.startSpan(req.path); + + span.setTag(Tags.SPAN_KIND, Tags.SPAN_KIND_RPC_SERVER); + span.setTag(Tags.HTTP_URL, req.url); + span.setTag(Tags.HTTP_METHOD, req.method); + + req.span = span; + + res.on('finish', () => { + span.setTag(Tags.HTTP_STATUS_CODE, res.statusCode); + span.finish(); + }); + + next(); +}; diff --git a/health-services/project-factory/src/server/utils/Pagination.ts b/health-services/project-factory/src/server/utils/Pagination.ts new file mode 100644 index 00000000000..29cdf043cb7 --- /dev/null +++ b/health-services/project-factory/src/server/utils/Pagination.ts @@ -0,0 +1,6 @@ +export interface Pagination { + offset?: number; + limit?: number; + sortBy?: string; + sortOrder?: 'ASC' | 'DESC'; +} diff --git a/health-services/project-factory/src/server/utils/boundaryUtils.ts b/health-services/project-factory/src/server/utils/boundaryUtils.ts new file mode 100644 index 00000000000..40aa4f437ed --- /dev/null +++ b/health-services/project-factory/src/server/utils/boundaryUtils.ts @@ -0,0 +1,15 @@ +import config from "../config/index"; + + + +export const getBoundaryColumnName = () => { + // Construct Boundary column name from the config + return config?.boundary?.boundaryCode; +}; + +// Function to generate localisation module name based on hierarchy type +export const getBoundaryTabName = () => { + // Construct Boundary tab name from the config + return config?.boundary?.boundaryTab; +}; + diff --git a/health-services/project-factory/src/server/utils/campaignMappingUtils.ts b/health-services/project-factory/src/server/utils/campaignMappingUtils.ts new file mode 100644 index 00000000000..f4698f4b77d --- /dev/null +++ b/health-services/project-factory/src/server/utils/campaignMappingUtils.ts @@ -0,0 +1,447 @@ +import createAndSearch from "../config/createAndSearch"; +import config from "../config"; +import { getDataFromSheet, getLocalizedMessagesHandlerViaRequestInfo, throwError } from "./genericUtils"; +import { getFormattedStringForDebug, logger } from "./logger"; +import { defaultheader, httpRequest } from "./request"; +import { produceModifiedMessages } from "../kafka/Producer"; +import { enrichAndPersistCampaignWithError, getLocalizedName } from "./campaignUtils"; +import { campaignStatuses, resourceDataStatuses } from "../config/constants"; +import { createCampaignService } from "../service/campaignManageService"; +import { persistTrack } from "./processTrackUtils"; +import { processTrackTypes, processTrackStatuses } from "../config/constants"; +import { createProjectFacilityHelper, createProjectResourceHelper, createStaffHelper } from "../api/genericApis"; + + +async function createBoundaryWithProjectMapping(projects: any, boundaryWithProject: any) { + for (const project of projects) { + if (project?.address?.boundary) { + boundaryWithProject[project?.address?.boundary] = project?.id + } + if (project?.descendants && Array.isArray(project?.descendants) && project?.descendants?.length > 0) { + await createBoundaryWithProjectMapping(project?.descendants, boundaryWithProject) + } + } +} + +function getPvarIds(messageObject: any) { + const deliveryRules = messageObject?.CampaignDetails?.deliveryRules; + const uniquePvarIds = new Set(); // Create a Set to store unique pvar IDs + if (deliveryRules) { + for (const deliveryRule of deliveryRules) { + const products = deliveryRule?.products; + if (products) { + for (const product of products) { + uniquePvarIds.add(product?.value); // Add pvar ID to the Set + } + } + } + } + return Array.from(uniquePvarIds); // Convert Set to array before returning +} + +function trimBoundaryCodes(root: any) { + if (root) { + root.code = root.code.trim(); // Trim the code + + // Recursively trim the codes in the children + for (const child of root.children) { + trimBoundaryCodes(child); + } + } +} + +async function getAllBoundaries(messageObject: any, tenantId: any, rootBoundary: any, hierarchyType: any) { + const BoundarySearchBody = { + RequestInfo: messageObject?.RequestInfo, + } + const params = { + tenantId, + codes: rootBoundary, + hierarchyType, + includeChildren: true + } + const header = { + ...defaultheader, + cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, + } + const boundaryResponse = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, BoundarySearchBody, params, undefined, undefined, header); + trimBoundaryCodes(boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]); + return boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0] +} + +// Function to find the path to a given boundary code +function findPath(root: any, code: string, path: any[] = []) { + if (root.code === code) { + return [...path, root]; + } + for (const child of root.children) { + const result: any = findPath(child, code, [...path, root]); + if (result) return result; + } + return null; +} + +// Function to find the common parent for multiple codes +function findCommonParent(codes: string[], root: any) { + if (codes.length === 0) return null; + + // Find paths for all codes + const paths = codes.map(code => findPath(root, code)).filter(path => path !== null); + + if (paths.length === 0) return null; + + // Compare paths to find the common ancestor + let commonParent: any = null; + + for (let i = 0; i < Math.min(...paths.map(path => path.length)); i++) { + const currentParent = paths[0][i]; + if (paths.every(path => path[i] && path[i].code === currentParent.code)) { + commonParent = currentParent; + } else { + break; + } + } + + return commonParent?.code; +} + +function mapBoundaryCodes(resource: any, code: string, boundaryCode: string, boundaryCodes: any, allBoundaries: any) { + // Split boundary codes if they have comma separated values + const boundaryCodesArray = boundaryCode.split(',').map((bc: string) => bc.trim()); + if (resource?.type == "user" && boundaryCodesArray?.length > 1 && config.user.mapUserViaCommonParent) { + const commonParent = findCommonParent(boundaryCodesArray, allBoundaries); + if (commonParent) { + logger.info(`Boundary Codes Array ${boundaryCodesArray.join(",")} for resource ${resource?.type} has common parent ${commonParent}`) + if (!boundaryCodes[resource?.type]) { + boundaryCodes[resource?.type] = {}; + } + if (!boundaryCodes[resource?.type][commonParent]) { + boundaryCodes[resource?.type][commonParent] = []; + } + boundaryCodes[resource?.type][commonParent].push(code); + logger.info(`Common Parent Boundary code ${commonParent} mapped to resource ${resource?.type} with code ${code}`) + } + } + else { + boundaryCodesArray.forEach((trimmedBC: string) => { + // Trim any leading or trailing spaces + if (!boundaryCodes[resource?.type]) { + boundaryCodes[resource?.type] = {}; + } + if (!boundaryCodes[resource?.type][trimmedBC]) { + boundaryCodes[resource?.type][trimmedBC] = []; + } + boundaryCodes[resource?.type][trimmedBC].push(code); + logger.info(`Boundary code ${trimmedBC} mapped to resource ${resource?.type} with code ${code}`) + }); + } +} + +async function enrichBoundaryCodes(resources: any[], messageObject: any, boundaryCodes: any, sheetName: any) { + const localizationMap: any = messageObject?.localizationMap + const allBoundaries = await getAllBoundaries(messageObject, messageObject?.Campaign?.tenantId, messageObject?.Campaign?.boundaryCode, messageObject?.Campaign?.hierarchyType); + for (const resource of resources) { + const processedFilestoreId = resource?.processedFilestoreId; + if (processedFilestoreId) { + 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"; + if (createAndSearch?.[resource?.type]?.activeColumn && createAndSearch?.[resource?.type]?.activeColumnName) { + var activeColumn = getLocalizedName(createAndSearch?.[resource?.type]?.activeColumnName, localizationMap); + active = data[activeColumn]; + } + if (boundaryCode && active == "Active") { + mapBoundaryCodes(resource, code, boundaryCode, boundaryCodes, allBoundaries); + } + } + else { + logger.info(`Code ${code} is somehow null or empty for resource ${resource?.type} for uniqueCodeColumn ${uniqueCodeColumn}`) + } + } + } + } +} + + +async function enrichBoundaryWithProject(messageObject: any, boundaryWithProject: any, boundaryCodes: any) { + const projectSearchBody = { + RequestInfo: messageObject?.RequestInfo, + Projects: [{ + id: messageObject?.Campaign?.rootProjectId, + tenantId: messageObject?.Campaign?.tenantId + }], + apiOperation: "SEARCH" + } + const params = { + tenantId: messageObject?.Campaign?.tenantId, + offset: 0, + limit: 100, + includeDescendants: true + } + logger.info("params : " + JSON.stringify(params)); + logger.info("boundaryCodes : " + JSON.stringify(boundaryCodes)); + const response = await httpRequest(config.host.projectHost + config.paths.projectSearch, projectSearchBody, params); + await createBoundaryWithProjectMapping(response?.Project, boundaryWithProject); + logger.debug(`boundaryWise Project mapping : ${getFormattedStringForDebug(boundaryWithProject)}`); + logger.info("boundaryCodes mapping : " + JSON.stringify(boundaryCodes)); +} + +async function getProjectMappingBody(messageObject: any, boundaryWithProject: any, boundaryCodes: any) { + const Campaign: any = { + id: messageObject?.Campaign?.id, + tenantId: messageObject?.Campaign?.tenantId, + CampaignDetails: [] + } + for (const key of Object.keys(boundaryWithProject)) { + if (boundaryWithProject[key]) { + const resources: any[] = []; + const pvarIds = getPvarIds(messageObject); + if (pvarIds && 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({ + type: type == "user" ? "staff" : type, + resourceIds: [...boundaryCodes[type][key]] + }) + } + } + Campaign.CampaignDetails.push({ + projectId: boundaryWithProject[key], + resources: resources + }) + } + } + return { + RequestInfo: messageObject?.RequestInfo, + Campaign: Campaign, + CampaignDetails: messageObject?.CampaignDetails + } +} + +async function fetchAndMap(resources: any[], messageObject: 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)); + 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) { + var searchBody = { + RequestInfo: messageObject?.RequestInfo, + SearchCriteria: { + id: [resourceDetailId], + tenantId: messageObject?.Campaign?.tenantId + } + } + const response: any = await httpRequest(config.host.projectFactoryBff + "project-factory/v1/data/_search", searchBody); + return response?.ResourceDetails?.[0]; +} + +async function validateMappingId(messageObject: any, id: string) { + const searchBody = { + RequestInfo: messageObject?.RequestInfo, + CampaignDetails: { + ids: [id], + tenantId: messageObject?.Campaign?.tenantId, + } + } + const response: any = await httpRequest(config.host.projectFactoryBff + "project-factory/v1/project-type/search", searchBody); + if (!response?.CampaignDetails?.[0]) { + throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "Campaign with id " + id + " does not exist"); + } + return response?.CampaignDetails?.[0]; +} + +async function processCampaignMapping(messageObject: any) { + const resourceDetailsIds = messageObject?.Campaign?.resourceDetailsIds + const id = messageObject?.Campaign?.id + if (!id) { + throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "Campaign id is missing"); + } + const campaignDetails = await validateMappingId(messageObject, id); + if (campaignDetails?.status == campaignStatuses.inprogress) { + logger.info("Campaign Already In Progress and Mapped"); + } + else { + 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) + } + await persistTrack(id, processTrackTypes.confirmingResourceCreation, processTrackStatuses.completed); + await fetchAndMap(resources, messageObject); + } +} + +export async function handleCampaignMapping(messageObject: any) { + try { + logger.info("Received a message for campaign mapping"); + logger.debug("Message Object of campaign mapping: " + getFormattedStringForDebug(messageObject)); + await processCampaignMapping(messageObject); + } catch (error) { + logger.error("Error in campaign mapping: " + error); + await enrichAndPersistCampaignWithError(messageObject, error); + } +} + +export async function handleStaffMapping(mappingArray: any[], campaignId: string, messageObject: any) { + await persistTrack(campaignId, processTrackTypes.staffMapping, processTrackStatuses.inprogress); + try { + const promises = [] + logger.debug("Array of staff mapping: " + getFormattedStringForDebug(mappingArray)); + for (const staffMapping of mappingArray) { + const { resource, projectId, resouceBody, tenantId, startDate, endDate } = staffMapping; + for (const resourceId of resource?.resourceIds) { + promises.push(createStaffHelper(resourceId, projectId, resouceBody, tenantId, startDate, endDate)) + } + } + await Promise.all(promises); + } catch (error: any) { + logger.error("Error in staff mapping: " + error); + await persistTrack(campaignId, processTrackTypes.staffMapping, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + await enrichAndPersistCampaignWithError(messageObject, error); + throw new Error(error) + } + await persistTrack(campaignId, processTrackTypes.staffMapping, processTrackStatuses.completed); +} + +export async function handleResourceMapping(mappingArray: any, campaignId: any, messageObject: any) { + await persistTrack(campaignId, processTrackTypes.resourceMapping, processTrackStatuses.inprogress); + try { + const promises = [] + logger.debug("Arrray of resource mapping: " + getFormattedStringForDebug(mappingArray)); + for (const mapping of mappingArray) { + const { resource, projectId, resouceBody, tenantId, startDate, endDate } = mapping; + for (const resourceId of resource?.resourceIds) { + promises.push(createProjectResourceHelper(resourceId, projectId, resouceBody, tenantId, startDate, endDate)); + } + } + await Promise.all(promises); + } catch (error: any) { + logger.error("Error in resource mapping: " + error); + await persistTrack(campaignId, processTrackTypes.resourceMapping, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + await enrichAndPersistCampaignWithError(messageObject, error); + throw new Error(error) + } + await persistTrack(campaignId, processTrackTypes.resourceMapping, processTrackStatuses.completed); +} + +export async function handleFacilityMapping(mappingArray: any, campaignId: any, messageObject: any) { + await persistTrack(campaignId, processTrackTypes.facilityMapping, processTrackStatuses.inprogress); + try { + const promises = [] + logger.debug("Array of facility mapping: " + getFormattedStringForDebug(mappingArray)); + for (const mapping of mappingArray) { + const { resource, projectId, resouceBody, tenantId } = mapping; + for (const resourceId of resource?.resourceIds) { + promises.push(createProjectFacilityHelper(resourceId, projectId, resouceBody, tenantId)); + } + } + await Promise.all(promises); + } catch (error: any) { + logger.error("Error in facility mapping: " + error); + await persistTrack(campaignId, processTrackTypes.facilityMapping, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + await enrichAndPersistCampaignWithError(messageObject, error); + throw new Error(error) + } + await persistTrack(campaignId, processTrackTypes.facilityMapping, processTrackStatuses.completed); +} + +export async function processMapping(mappingObject: any) { + try { + if (mappingObject?.mappingArray && Array.isArray(mappingObject?.mappingArray) && mappingObject?.mappingArray?.length > 0) { + const resourceMappingArray = mappingObject?.mappingArray?.filter((mappingObject: any) => mappingObject?.type == "resource"); + const facilityMappingArray = mappingObject?.mappingArray?.filter((mappingObject: any) => mappingObject?.type == "facility"); + const staffMappingArray = mappingObject?.mappingArray?.filter((mappingObject: any) => mappingObject?.type == "staff"); + await handleResourceMapping(resourceMappingArray, mappingObject?.CampaignDetails?.id, mappingObject); + await handleFacilityMapping(facilityMappingArray, mappingObject?.CampaignDetails?.id, mappingObject); + await handleStaffMapping(staffMappingArray, mappingObject?.CampaignDetails?.id, mappingObject); + } + logger.info("Mapping completed successfully for campaign: " + mappingObject?.CampaignDetails?.id); + mappingObject.CampaignDetails.status = campaignStatuses.inprogress + const produceMessage: any = { + CampaignDetails: mappingObject?.CampaignDetails + } + await produceModifiedMessages(produceMessage, config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC) + await persistTrack(mappingObject?.CampaignDetails?.id, processTrackTypes.campaignCreation, processTrackStatuses.completed) + } catch (error) { + logger.error("Error in campaign mapping: " + error); + await enrichAndPersistCampaignWithError(mappingObject, error); + } +} + + +export { + processCampaignMapping, + validateMappingId +} diff --git a/health-services/project-factory/src/server/utils/campaignUtils.ts b/health-services/project-factory/src/server/utils/campaignUtils.ts new file mode 100644 index 00000000000..1fbf424ecf9 --- /dev/null +++ b/health-services/project-factory/src/server/utils/campaignUtils.ts @@ -0,0 +1,1892 @@ + +import { defaultheader, httpRequest } from "./request"; +import config from "../config/index"; +import { v4 as uuidv4 } from 'uuid'; +import { produceModifiedMessages } from "../kafka/Producer"; +import { confirmProjectParentCreation, createProjectCampaignResourcData, getCampaignSearchResponse, getHierarchy, handleResouceDetailsError, projectCreate } from "../api/campaignApis"; +import { getCampaignNumber, createAndUploadFile, getSheetData, createExcelSheet, getAutoGeneratedBoundaryCodesHandler, createBoundaryEntities, createBoundaryRelationship, getMDMSV1Data, getTargetSheetDataAfterCode, callMdmsTypeSchema, getSheetDataFromWorksheet } from "../api/genericApis"; +import { getFormattedStringForDebug, logger } from "./logger"; +import createAndSearch from "../config/createAndSearch"; +import { addDataToSheet, createBoundaryDataMainSheet, createReadMeSheet, findMapValue, getBoundaryRelationshipData, getConfigurableColumnHeadersFromSchemaForTargetSheet, getLocalizedHeaders, getLocalizedMessagesHandler, getMdmsDataBasedOnCampaignType, modifyBoundaryData, replicateRequest, throwError } from "./genericUtils"; +import { enrichProjectDetailsFromCampaignDetails } from "./transforms/projectTypeUtils"; +import { executeQuery } from "./db"; +import { campaignDetailsTransformer, genericResourceTransformer } from "./transforms/searchResponseConstructor"; +import { transformAndCreateLocalisation } from "./transforms/localisationMessageConstructor"; +import { campaignStatuses, headingMapping, processTrackStatuses, processTrackTypes, resourceDataStatuses } from "../config/constants"; +import { getBoundaryColumnName, getBoundaryTabName } from "./boundaryUtils"; +import { searchProjectTypeCampaignService } from "../service/campaignManageService"; +import { validateBoundaryOfResouces } from "../validators/campaignValidators"; +import { getExcelWorkbookFromFileURL, getNewExcelWorkbook, lockTargetFields, updateFontNameToRoboto } from "./excelUtils"; +import { areBoundariesSame, callGenerateIfBoundariesDiffer } from "./generateUtils"; +import { createProcessTracks, persistTrack } from "./processTrackUtils"; +import { generateDynamicTargetHeaders, isDynamicTargetTemplateForProjectType, updateTargetColumnsIfDeliveryConditionsDifferForSMC } from "./targetUtils"; +const _ = require('lodash'); + + + +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; + } + }); + } + + // 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; + } + }); + } + 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 }; + } +} + + +function findColumns(worksheet: any) { + 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 = {} + + findAndChangeColumns(worksheet, columns); + + makeColumns(worksheet, range, columns); + + updateRange(range, worksheet); + + 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 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 = 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); + 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; +} + +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; + } + }); + + const responseData = await createAndUploadFile(workbook, request); + + logger.info('File updated successfully:' + JSON.stringify(responseData)); + if (responseData?.[0]?.fileStoreId) { + request.body.ResourceDetails.processedFileStoreId = responseData?.[0]?.fileStoreId; + } else { + throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); + } +} +async function updateStatusFileForTargets(request: any, localizationMap?: { [key: string]: string }) { + const fileStoreId = request?.body?.ResourceDetails?.fileStoreId; + const tenantId = request?.body?.ResourceDetails?.tenantId; + const createAndSearchConfig = createAndSearch[request?.body?.ResourceDetails?.type]; + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: tenantId, fileStoreIds: fileStoreId }, "get"); + + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 500, "INVALID_FILE"); + } + + + const 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; + } else { + throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); + } +} + + +function convertToType(dataToSet: any, type: any) { + switch (type) { + case "string": + return String(dataToSet); + case "number": + return Number(dataToSet); + case "boolean": + // Convert to boolean assuming any truthy value should be true and falsy should be false + return Boolean(dataToSet); + // Add more cases if needed for other types + default: + // If type is not recognized, keep dataToSet as it is + return dataToSet; + } +} + +function setTenantId( + resultantElement: any, + requestBody: any, + createAndSearchConfig: any +) { + if (createAndSearchConfig?.parseArrayConfig?.tenantId) { + const tenantId = _.get(requestBody, createAndSearchConfig?.parseArrayConfig?.tenantId?.getValueViaPath); + _.set(resultantElement, createAndSearchConfig?.parseArrayConfig?.tenantId?.resultantPath, tenantId); + } + +} + + +async function processData(request: any, dataFromSheet: any[], createAndSearchConfig: any, localizationMap?: { [key: string]: string }) { + const parseLogic = createAndSearchConfig?.parseArrayConfig?.parseLogic; + const requiresToSearchFromSheet = createAndSearchConfig?.requiresToSearchFromSheet; + var createData = [], searchData = []; + for (const data of dataFromSheet) { + const resultantElement: any = {}; + for (const element of parseLogic) { + if (element?.resultantPath) { + const localizedSheetColumnName = getLocalizedName(element.sheetColumnName, localizationMap); + let dataToSet = _.get(data, localizedSheetColumnName); + if (element.conversionCondition) { + dataToSet = element.conversionCondition[dataToSet]; + } + if (element.type) { + dataToSet = convertToType(dataToSet, element.type); + } + _.set(resultantElement, element.resultantPath, dataToSet); + } + } + resultantElement["!row#number!"] = data["!row#number!"]; + var addToCreate = true; + if (requiresToSearchFromSheet) { + for (const key of requiresToSearchFromSheet) { + const localizedSheetColumnName = getLocalizedName(key.sheetColumnName, localizationMap); + if (data[localizedSheetColumnName]) { + searchData.push(resultantElement) + addToCreate = false; + break; + } + } + } + if (addToCreate) { + createData.push(resultantElement) + } + } + return { searchData, createData }; +} + +function setTenantIdAndSegregate(processedData: any, createAndSearchConfig: any, requestBody: any) { + for (const resultantElement of processedData.createData) { + setTenantId(resultantElement, requestBody, createAndSearchConfig); + } + for (const resultantElement of processedData.searchData) { + setTenantId(resultantElement, requestBody, createAndSearchConfig); + } + return processedData; +} + +// Original function divided into two parts +async function convertToTypeData(request: any, dataFromSheet: any[], createAndSearchConfig: any, requestBody: any, localizationMap?: { [key: string]: string }) { + const processedData = await processData(request, dataFromSheet, createAndSearchConfig, localizationMap); + return setTenantIdAndSegregate(processedData, createAndSearchConfig, requestBody); +} + +function updateActivityResourceId(request: any) { + if (request?.body?.Activities && Array.isArray(request?.body?.Activities)) { + for (const activity of request?.body?.Activities) { + activity.resourceDetailsId = request?.body?.ResourceDetails?.id + } + } +} + +async function generateProcessedFileAndPersist(request: any, localizationMap?: { [key: string]: string }) { + if (request.body.ResourceDetails.type == 'boundaryWithTarget') { + await updateStatusFileForTargets(request, localizationMap); + } else { + if (request.body.ResourceDetails.type !== "boundary") { + await updateStatusFile(request, localizationMap); + } + } + updateActivityResourceId(request); + request.body.ResourceDetails = { + ...request?.body?.ResourceDetails, + status: request.body.ResourceDetails.status != resourceDataStatuses.invalid ? resourceDataStatuses.completed : resourceDataStatuses.invalid, + auditDetails: { + ...request?.body?.ResourceDetails?.auditDetails, + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now() + }, + additionalDetails: { ...request?.body?.ResourceDetails?.additionalDetails, sheetErrors: request?.body?.additionalDetailsErrors } || {} + }; + const persistMessage: any = { ResourceDetails: request.body.ResourceDetails } + if (request?.body?.ResourceDetails?.action == "create") { + persistMessage.ResourceDetails.additionalDetails = {} + } + 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 activityObject = request?.body?.Activities; + 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; + } + } + return ""; +} + +function enrichRootProjectId(requestBody: any) { + var rootBoundary; + for (const boundary of requestBody?.CampaignDetails?.boundaries) { + if (boundary?.isRoot) { + rootBoundary = boundary?.code + break; + } + } + if (rootBoundary) { + requestBody.CampaignDetails.projectId = requestBody?.boundaryProjectMapping?.[rootBoundary]?.projectId || null + } + requestBody.CampaignDetails.projectId = requestBody.CampaignDetails.projectId || null +} + +async function enrichAndPersistCampaignWithError(requestBody: any, error: any) { + requestBody.CampaignDetails = requestBody?.CampaignDetails || {} + const action = requestBody?.CampaignDetails?.action; + requestBody.CampaignDetails.campaignNumber = requestBody?.CampaignDetails?.campaignNumber || null + requestBody.CampaignDetails.campaignDetails = requestBody?.CampaignDetails?.campaignDetails || { deliveryRules: requestBody?.CampaignDetails?.deliveryRules, resources: requestBody?.CampaignDetails?.resources || [], boundaries: requestBody?.CampaignDetails?.boundaries || [] }; + requestBody.CampaignDetails.status = campaignStatuses?.failed; + requestBody.CampaignDetails.boundaryCode = getRootBoundaryCode(requestBody?.CampaignDetails?.boundaries) || null + requestBody.CampaignDetails.projectType = requestBody?.CampaignDetails?.projectType || null; + requestBody.CampaignDetails.hierarchyType = requestBody?.CampaignDetails?.hierarchyType || null; + requestBody.CampaignDetails.additionalDetails = requestBody?.CampaignDetails?.additionalDetails || {}; + requestBody.CampaignDetails.startDate = requestBody?.CampaignDetails?.startDate || null + requestBody.CampaignDetails.endDate = requestBody?.CampaignDetails?.endDate || null + requestBody.CampaignDetails.auditDetails = { + createdBy: requestBody?.RequestInfo?.userInfo?.uuid, + createdTime: Date.now(), + lastModifiedBy: requestBody?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now(), + } + if (action == "create" && !requestBody?.CampaignDetails?.projectId) { + enrichRootProjectId(requestBody); + } + else if (!requestBody?.CampaignDetails?.projectId) { + requestBody.CampaignDetails.projectId = null + } + requestBody.CampaignDetails.additionalDetails = { + ...requestBody?.CampaignDetails?.additionalDetails, + error: String((error?.message + (error?.description ? ` : ${error?.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) { + 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 + 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 || [] +} + + +async function enrichAndPersistCampaignForUpdate(request: any, firstPersist: boolean = false) { + const action = request?.body?.CampaignDetails?.action; + const existingCampaignDetails = request?.body?.ExistingCampaignDetails; + callGenerateIfBoundariesDiffer(request); + if (existingCampaignDetails) { + if (areBoundariesSame(existingCampaignDetails?.boundaries, request?.body?.CampaignDetails?.boundaries)) { + updateTargetColumnsIfDeliveryConditionsDifferForSMC(request); + } + } + const ExistingCampaignDetails = request?.body?.ExistingCampaignDetails; + var updatedInnerCampaignDetails = {} + enrichInnerCampaignDetails(request, updatedInnerCampaignDetails) + 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 + 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 +} + +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)}`); + await produceModifiedMessages(requestBody, config?.kafka?.KAFKA_START_CAMPAIGN_MAPPING_TOPIC); + } +} + +function removeBoundariesFromRequest(request: any) { + if (request?.body?.CampaignDetails?.boundaries && Array.isArray(request?.body?.CampaignDetails?.boundaries) && request?.body?.CampaignDetails?.boundaries?.length > 0) { + request.body.CampaignDetails.boundaries = request?.body?.CampaignDetails?.boundaries?.filter((boundary: any) => !boundary?.insertedAfter) + } +} + +async function 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?.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; +} + + + + + + +function getCodeMappingsOfExistingBoundaryCodes(withBoundaryCode: any[]) { + const countMap = new Map<{ key: string, value: string }, number>(); + const mappingMap = new Map<{ key: string, value: string }, string>(); + + withBoundaryCode.forEach((row: any[]) => { + const len = row.length; + if (len >= 3) { + let grandParentFound = false; + const grandParent = row[len - 3]; + if (findMapValue(mappingMap, grandParent)) { + const countMapArray = Array.from(countMap.entries()); + for (const [key, value] of countMapArray) { + if (_.isEqual(key, grandParent)) { + countMap.set(key, value + 1); + grandParentFound = true; + break; + } + } + if (grandParentFound == false) { + countMap.set(grandParent, 1); + } + } + } + mappingMap.set(row[len - 2], row[len - 1].value); + }); + return { mappingMap, countMap }; +} + + +function addBoundaryCodeToData(withBoundaryCode: any[], withoutBoundaryCode: any[], boundaryMap: Map) { + const boundaryDataWithBoundaryCode = withBoundaryCode; + const modifiedBoundaryDataWithBoundaryCode = boundaryDataWithBoundaryCode.map((array) => { + return array.map((obj: any) => { + if (obj.key === 'Boundary Code') { + return obj.value; + } else { + return obj; + } + }); + }); + + const boundaryDataForWithoutBoundaryCode = withoutBoundaryCode.map((row: any[]) => { + const boundaryName = row[row.length - 1]; // Get the last element of the row + const boundaryCode = findMapValue(boundaryMap, boundaryName); // Fetch corresponding boundary code from map + return [...row, boundaryCode]; // Append boundary code to the row and return updated row + }); + const boundaryDataForSheet = [...modifiedBoundaryDataWithBoundaryCode, ...boundaryDataForWithoutBoundaryCode]; + return boundaryDataForSheet; +} + +function prepareDataForExcel(boundaryDataForSheet: any, hierarchy: any[], boundaryMap: any) { + const data = boundaryDataForSheet.map((boundary: any[]) => { + const boundaryCode = boundary.pop(); + const boundaryValues = boundary.map(obj => obj.value); + const rowData = boundaryValues.concat(Array(Math.max(0, hierarchy.length - boundary.length)).fill('')); + const boundaryCodeIndex = hierarchy.length; + rowData[boundaryCodeIndex] = boundaryCode; + return rowData; + }); + return data; +} +function extractCodesFromBoundaryRelationshipResponse(boundaries: any[]): any { + const codes = new Set(); + for (const boundary of boundaries) { + codes.add(boundary.code); // Add code to the Set + if (boundary.children && boundary.children.length > 0) { + const childCodes = extractCodesFromBoundaryRelationshipResponse(boundary.children); // Recursively get child codes + childCodes.forEach((code: any) => codes.add(code)); // Add child codes to the Set + } + } + return codes; +} + + +async function getTotalCount(request: any) { + const CampaignDetails = request.body.CampaignDetails; + const { tenantId, pagination, ids, ...searchFields } = CampaignDetails; + let conditions = []; + let values = [tenantId]; + let index = 2; + const campaignsIncludeDates = searchFields?.campaignsIncludeDates + + for (const field in searchFields) { + if (searchFields[field] !== undefined && field != 'campaignsIncludeDates') { + if (field === 'startDate') { + const startDateSign = campaignsIncludeDates ? '<=' : '>='; + conditions.push(`startDate ${startDateSign} $${index}`); + values.push(searchFields[field]); + index++; + } else if (field === 'endDate') { + const endDateSign = campaignsIncludeDates ? '>=' : '<='; + conditions.push(`endDate ${endDateSign} $${index}`); + values.push(searchFields[field]); + index++; + } else if (field === 'campaignName') { + conditions.push(`${field} ILIKE '%' || $${index} || '%'`); + values.push(searchFields[field]); + index++; + } else if (field != 'status') { + conditions.push(`${field} = $${index}`); + values.push(searchFields[field]); + index++; + } + } + } + + let query = ` + SELECT count(*) + FROM ${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 = ` + 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; + } + + var status = searchFields?.status; + if (status) { + if (typeof status === 'string') { + status = [status]; // Convert string to array + } + const statusParams = status.map((param: any, i: any) => `$${index + i}`); // Increment index for each parameter + query += ` AND status IN (${statusParams.join(', ')})`; + values.push(...status); + } + + if (conditions.length > 0) { + query += ` AND ${conditions.join(' AND ')}`; + } + + if (pagination) { + query += '\n'; + + if (pagination.sortBy) { + query += `ORDER BY ${pagination.sortBy}`; + if (pagination.sortOrder) { + query += ` ${pagination.sortOrder.toUpperCase()}`; + } + query += '\n'; + } + + if (pagination.limit !== undefined) { + query += `LIMIT ${pagination.limit}`; + if (pagination.offset !== undefined) { + query += ` OFFSET ${pagination.offset}`; + } + query += '\n'; + } + } + + return { query, values }; +} + + + +async function executeSearchQuery(query: string, values: any[]) { + const queryResult = await executeQuery(query, values); + return campaignDetailsTransformer(queryResult?.rows); +} + +async function processDataSearchRequest(request: any) { + const { SearchCriteria } = request.body; + const query = buildWhereClauseForDataSearch(SearchCriteria); + const queryResult = await executeQuery(query.query, query.values); + request.body.ResourceDetails = genericResourceTransformer(queryResult?.rows);; +} + +function buildWhereClauseForDataSearch(SearchCriteria: any): { query: string; values: any[] } { + const { id, tenantId, type, status } = SearchCriteria; + let conditions = []; + let values = []; + + if (id && id.length > 0) { + conditions.push(`id = ANY($${values.length + 1})`); + values.push(id); + } + + if (tenantId) { + conditions.push(`tenantId = $${values.length + 1}`); + values.push(tenantId); + } + + if (type) { + conditions.push(`type = $${values.length + 1}`); + values.push(type); + } + + if (status) { + conditions.push(`status = $${values.length + 1}`); + values.push(status); + } + + const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''; + + return { + query: ` + SELECT * + FROM ${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; + + for (const boundaryResponse of boundaryResponses) { + const mapBoundary = (boundary: any) => { + if (!boundary.children || boundary.children.length === 0) { + const targetValue = codesTargetMapping[boundary.code]; + return targetValue ? targetValue : 0; + } + + let totalTargetValue = 0; + for (const child of boundary.children) { + const childTargetValue = mapBoundary(child); + totalTargetValue += childTargetValue; + } + codesTargetMapping[boundary.code] = totalTargetValue; + return totalTargetValue; + }; + mapBoundary(boundaryResponse); + } +} + + +async function processBoundary(boundaryResponse: any, boundaries: any, includeAllChildren: any, boundaryCodes: any, boundaryChildren: any) { + if (!boundaryResponse) return; + if (!boundaryCodes.has(boundaryResponse.code)) { + boundaries.push({ code: boundaryResponse?.code, type: boundaryResponse?.boundaryType, insertedAfter: true }); + boundaryCodes.add(boundaryResponse?.code); + } + if (includeAllChildren && boundaryResponse?.children && Array.isArray(boundaryResponse?.children) && boundaryResponse?.children?.length > 0) { + for (const child of boundaryResponse.children) { + processBoundary(child, boundaries, true, boundaryCodes, boundaryChildren); + } + } + else if (boundaryResponse?.children && Array.isArray(boundaryResponse?.children) && boundaryResponse?.children?.length > 0) { + for (const child of boundaryResponse.children) { + if (boundaryCodes.has(child.code) && boundaryChildren[child.code]) { + processBoundary(child, boundaries, true, boundaryCodes, boundaryChildren); + } + else if (boundaryCodes.has(child.code)) { + processBoundary(child, boundaries, false, boundaryCodes, boundaryChildren); + } + } + } +} + +async function addBoundaries(request: any, boundaryResponse: any, boundaryChildren: any) { + var { boundaries } = request?.body?.CampaignDetails; + var boundaryCodes = new Set(boundaries.map((boundary: any) => boundary.code)); + await processBoundary(boundaryResponse, boundaries, boundaryChildren[boundaryResponse?.code], boundaryCodes, boundaryChildren); + request.body.CampaignDetails.boundaries = boundaries +} + +async function addBoundariesForData(request: any, CampaignDetails: any) { + var { boundaries } = CampaignDetails; + const rootBoundary = getRootBoundaryCode(boundaries) + if (rootBoundary) { + const params = { + tenantId: request?.body?.ResourceDetails?.tenantId, + codes: rootBoundary, + hierarchyType: request?.body?.ResourceDetails?.hierarchyType, + includeChildren: true + } + const 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); + + if (parentIndex !== -1 && boundaryIndex !== -1 && parentIndex > boundaryIndex) { + reorderedBoundaries.splice(parentIndex + 1, 0, reorderedBoundaries.splice(boundaryIndex, 1)[0]); + break; + } + } + } + } +} + +async function reorderBoundariesOfDataAndValidate(request: any, localizationMap?: any) { + if (request?.body?.ResourceDetails?.campaignId) { + const searchBody = { + RequestInfo: request?.body?.RequestInfo, + CampaignDetails: { + ids: [request?.body?.ResourceDetails?.campaignId], + tenantId: request?.body?.ResourceDetails?.tenantId + } + } + const req: any = replicateRequest(request, searchBody) + const response = await searchProjectTypeCampaignService(req) + if (response?.CampaignDetails?.[0]) { + const CampaignDetails = response?.CampaignDetails?.[0] + await addBoundariesForData(request, CampaignDetails) + logger.debug("Boundaries after addition " + getFormattedStringForDebug(CampaignDetails?.boundaries)); + await validateBoundaryOfResouces(CampaignDetails, request, localizationMap) + } + else { + throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND", "Campaign not found while Validating sheet boundaries"); + } + } +} + +async function reorderBoundaries(request: any, localizationMap?: any) { + var { boundaries } = request?.body?.CampaignDetails; + const rootBoundary = getRootBoundaryCode(boundaries) + request.body.boundaryProjectMapping = {} + if (rootBoundary) { + const params = { + tenantId: request?.body?.CampaignDetails?.tenantId, + codes: rootBoundary, + hierarchyType: request?.body?.CampaignDetails?.hierarchyType, + includeChildren: true + } + const 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)); +} + +function convertToProjectsArray(Projects: any, currentArray: any = []) { + for (const project of Projects) { + const descendants = project?.descendants + delete project?.descendants + currentArray.push(project); + if (descendants && Array.isArray(descendants) && descendants?.length > 0) { + convertToProjectsArray(descendants, currentArray) + } + } + return currentArray; +} + +async function getRelatedProjects(request: any) { + const { projectId, tenantId } = request?.body?.CampaignDetails; + const projectSearchBody = { + RequestInfo: request?.body?.RequestInfo, + Projects: [ + { + id: projectId, + tenantId: tenantId + } + ] + } + const projectSearchParams = { + tenantId: tenantId, + offset: 0, + limit: 1, + includeDescendants: true + } + logger.info("Project search params " + JSON.stringify(projectSearchParams)) + 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") + } + } +} + +async function getCodesTarget(request: any, localizationMap?: any) { + const { tenantId, resources } = request?.body?.CampaignDetails; + const boundaryWithTargetResource = resources?.filter((resource: any) => resource?.type == "boundaryWithTarget"); + const fileId = boundaryWithTargetResource[0]?.filestoreId + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: tenantId, fileStoreIds: fileId }, "get"); + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 500, "DOWNLOAD_URL_NOT_FOUND"); + } + const codeColumnName = getLocalizedName(createAndSearch?.boundaryWithTarget?.boundaryValidation?.column, localizationMap) + const targetData = await getTargetSheetDataAfterCode(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']; + } + }); + } + logger.info("Boundary target mapping count" + Object.keys(boundaryTargetMapping)?.length); + return boundaryTargetMapping; +} + +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, boundaries, projectType, projectId } = request?.body?.CampaignDetails; + if (boundaries && projectType && !projectId) { + const projectTypeResponse = await getMDMSV1Data({}, 'HCM-PROJECT-TYPES', "projectTypes", tenantId); + var Projects: any = enrichProjectDetailsFromCampaignDetails(request?.body?.CampaignDetails, projectTypeResponse?.filter((types: any) => types?.code == projectType)?.[0]); + const projectCreateBody = { + RequestInfo: request?.body?.RequestInfo, + Projects + } + await reorderBoundaries(request, localizationMap) + boundaries = request?.body?.CampaignDetails?.boundaries; + for (const boundary of boundaries) { + Projects[0].address = { tenantId: tenantId, boundary: boundary?.code, boundaryType: boundary?.type } + if (request?.body?.boundaryProjectMapping?.[boundary?.code]?.parent) { + const parent = request?.body?.boundaryProjectMapping?.[boundary?.code]?.parent + await confirmProjectParentCreation(request, request?.body?.boundaryProjectMapping?.[parent]?.projectId) + Projects[0].parent = request?.body?.boundaryProjectMapping?.[parent]?.projectId + } + else { + Projects[0].parent = null + } + Projects[0].referenceID = request?.body?.CampaignDetails?.id + Projects[0].targets = [ + { + beneficiaryType: request?.body?.CampaignDetails?.additionalDetails?.beneficiaryType, + totalNo: request?.body?.CampaignDetails?.codesTargetMapping[boundary?.code], + targetNo: request?.body?.CampaignDetails?.codesTargetMapping[boundary?.code] + } + ] + await projectCreate(projectCreateBody, request) + } + } + } catch (error: any) { + console.log(error) + await persistTrack(request?.body?.CampaignDetails?.id, processTrackTypes.targetAndDeliveryRulesCreation, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + throw new Error(error) + } + await persistTrack(request?.body?.CampaignDetails?.id, processTrackTypes.targetAndDeliveryRulesCreation, processTrackStatuses.completed); +} + + +async function processAfterPersist(request: any, actionInUrl: any) { + try { + const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.CampaignDetails?.tenantId); + if (request?.body?.CampaignDetails?.action == "create") { + await persistTrack(request.body.CampaignDetails.id, processTrackTypes.validation, processTrackStatuses.completed); + await createProjectCampaignResourcData(request); + await createProject(request, actionInUrl, localizationMap) + await enrichAndPersistProjectCampaignRequest(request, actionInUrl, false, localizationMap) + } + else { + await updateProjectDates(request, actionInUrl); + await enrichAndPersistProjectCampaignRequest(request, actionInUrl, false, localizationMap) + } + } 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) +} + + +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 resultHierarchy = getLocalizedHeaders( + modifiedHierarchy, + 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 responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); + if (!(isSourceMicroplan)) { + const mainSheet = workbook.addWorksheet(getLocalizedName(getBoundaryTabName(), localizationMap)); + const columnWidths = Array(12).fill(30); + mainSheet.columns = columnWidths.map(width => ({ width })); + // mainSheetData.forEach(row => mainSheet.addRow(row)); + addDataToSheet(mainSheet, mainSheetData, 'F3842D', 30, false, true); + mainSheet.state = 'hidden'; + } + logger.info("appending different districts tab in the sheet started") + await appendDistricts(request, workbook, uniqueDistrictsForMainSheet, differentTabsBasedOnLevel, boundaryData, localizationMap, districtLevelRowBoundaryCodeMap, hierarchy, campaignObject); + 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) { + const configurableColumnHeadersFromSchemaForTargetSheet = await getConfigurableColumnHeadersFromSchemaForTargetSheet(request, hierarchy, boundaryData, differentTabsBasedOnLevel, campaignObject, localizationMap); + for (const uniqueData of uniqueDistrictsForMainSheet) { + const uniqueDataFromLevelForDifferentTabs = uniqueData.slice(uniqueData.lastIndexOf('#') + 1); + logger.info(`generating the boundary data for ${uniqueDataFromLevelForDifferentTabs} - ${differentTabsBasedOnLevel}`) + 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, campaignObject); + logger.info(`${uniqueDataFromLevelForDifferentTabs} - ${differentTabsBasedOnLevel} boundary data generation completed`) + } + } +} + +async function createNewSheet(request: any, workbook: any, newSheetData: any, uniqueData: any, localizationMap: any, districtLevelRowBoundaryCodeMap: any, localizedHeaders: any, campaignObject: any) { + const newSheet = workbook.addWorksheet(getLocalizedName(districtLevelRowBoundaryCodeMap.get(uniqueData), localizationMap)); + addDataToSheet(newSheet, newSheetData, 'F3842D', 40); + let columnsNotToBeFreezed: any; + const boundaryCodeColumnIndex = localizedHeaders.findIndex((header: any) => header === getLocalizedName(config?.boundary?.boundaryCode, localizationMap)); + 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, localizationMap?: any): any { + + // Step 2: Slice the boundary code up to the last underscore + const slicedBoundaryCode = targetBoundaryCode.slice(0, targetBoundaryCode.lastIndexOf('_') + 1); + + // Step 3: Filter the rows that contain the sliced boundary code + const modifiedFilteredData = districtDataFiltered.filter((row: any, index: any) => { + // Extract the boundary code from the current row + const localizedBoundaryCode = getLocalizedName(getBoundaryColumnName(), localizationMap); + const boundaryCode = row[localizedBoundaryCode]; + // Check if the boundary code starts with the sliced boundary code + return boundaryCode.startsWith(slicedBoundaryCode); + }); + // Step 4: Return the modified filtered data + return modifiedFilteredData; +} + +async function generateFilteredBoundaryData(request: any, 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) + }; + } + + const filteredChildren: any[] = []; + boundary.children.forEach((child: any) => { + const matchingFilter = boundaryFilters.find((f: any) => f.code === child.code && f.boundaryType === child.boundaryType); + if (matchingFilter) { + filteredChildren.push(filterRecursive(child)); + } + }); + return { + ...boundary, + children: filteredChildren + }; + } + const filteredData = boundaryData.map(filterRecursive); + return filteredData; +} + + +function generateHierarchy(boundaries: any[]) { + // Create an object to store boundary types and their parents + const parentMap: any = {}; + + // Populate the object with boundary types and their parents + for (const boundary of boundaries) { + parentMap[boundary.boundaryType] = boundary.parentBoundaryType; + } + + // Traverse the hierarchy to generate the hierarchy list + const hierarchyList = []; + for (const boundaryType in parentMap) { + if (Object.prototype.hasOwnProperty.call(parentMap, boundaryType)) { + const parentBoundaryType = parentMap[boundaryType]; + if (parentBoundaryType === null) { + // This boundary type has no parent, add it to the hierarchy list + hierarchyList.push(boundaryType); + // Traverse its children recursively + traverseChildren(boundaryType, parentMap, hierarchyList); + } + } + } + return hierarchyList; +} + +function traverseChildren(parent: any, parentMap: any, hierarchyList: any[]) { + for (const boundaryType in parentMap) { + if (Object.prototype.hasOwnProperty.call(parentMap, boundaryType)) { + const parentBoundaryType = parentMap[boundaryType]; + if (parentBoundaryType === parent) { + // This boundary type has the current parent, add it to the hierarchy list + hierarchyList.push(boundaryType); + // Traverse its children recursively + traverseChildren(boundaryType, parentMap, hierarchyList); + } + } + } +} + +function createBoundaryMap(boundaries: any[], boundaryMap: Map): void { + for (const boundary of boundaries) { + boundaryMap.set(boundary.code, boundary.boundaryType); + if (boundary.children.length > 0) { + createBoundaryMap(boundary.children, boundaryMap); + } + } +} + +async function boundaryBulkUpload(request: any, localizationMap?: any) { + try { + logger.info("Boundary Relationship Creation Starts"); + await autoGenerateBoundaryCodes(request, localizationMap); + await generateProcessedFileAndPersist(request); + } + catch (error: any) { + 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([...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"); + 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; +} + +function modifyBoundaryDataHeaders(boundaryData: any[], hierarchy: any[], localizationMap?: any) { + const updatedData = boundaryData.map((obj: any) => { + const updatedObj: { [key: string]: string | undefined } = {}; // Updated object with modified keys + + let hierarchyIndex = 0; // Track the index of the hierarchy array + + for (const key in obj) { + if (key != getLocalizedName(config?.boundary?.boundaryCode, localizationMap)) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + const hierarchyKey = hierarchy[hierarchyIndex]; // Get the key from the hierarchy array + updatedObj[hierarchyKey] = obj[key]; // Map the key to the updated object + hierarchyIndex++; // Move to the next key in the hierarchy array + } + } + else { + updatedObj[key] = obj[key]; + } + } + + + return updatedObj; + }); + return updatedData; +} + +function modifyChildParentMap(childParentMap: Map, boundaryMap: Map): Map { + const modifiedMap: Map = new Map(); + + // Iterate over each entry in childParentMap + childParentMap.forEach((value, key) => { + // Get the modified key and value from boundaryMap + const modifiedKey = findMapValue(boundaryMap, key) || null; + const modifiedValue = value ? findMapValue(boundaryMap, value) : null; + + // Set the modified key-value pair in modifiedMap + modifiedMap.set(modifiedKey, modifiedValue); + }); + + return modifiedMap; +} + + +async function convertSheetToDifferentTabs(request: any, boundaryData: any, differentTabsBasedOnLevel: any, localizationMap?: any) { + // create different tabs on the level of hierarchy we want to + const updatedWorkbook = await appendSheetsToWorkbook(request, boundaryData, differentTabsBasedOnLevel, localizationMap); + // upload the excel and generate file store id + const boundaryDetails = await createAndUploadFile(updatedWorkbook, request); + return boundaryDetails; +} + +async function getBoundaryDataAfterGeneration(result: any, request: any, localizationMap?: any) { + const fileStoreId = result[0].fileStoreId; + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: request?.query?.tenantId, fileStoreIds: fileStoreId }, "get"); + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 400, "INVALID_FILE"); + } + const boundaryData = await getSheetData(fileResponse?.fileStoreIds?.[0]?.url, getBoundaryTabName(), false, undefined, localizationMap); + return boundaryData; +} + +function getLocalizedName(expectedName: string, localizationMap?: { [key: string]: string }) { + if (!localizationMap || !(expectedName in localizationMap)) { + return expectedName; + } + const localizedName = localizationMap[expectedName]; + return localizedName; +} + +async function getTargetBoundariesRelatedToCampaignId(request: any, localizationMap?: any) { + let CampaignDetails: any; + if (request?.body?.ResourceDetails?.campaignId) { + const searchBody = { + RequestInfo: request?.body?.RequestInfo, + CampaignDetails: { + ids: [request?.body?.ResourceDetails?.campaignId], + tenantId: request?.body?.ResourceDetails?.tenantId + } + } + const req: any = replicateRequest(request, searchBody) + const response = await searchProjectTypeCampaignService(req) + if (response?.CampaignDetails?.[0]) { + CampaignDetails = response?.CampaignDetails?.[0] + await addBoundariesForData(request, CampaignDetails) + } + else { + throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND", "Campaign not found while Validating sheet boundaries"); + } + } + return CampaignDetails?.boundaries; +} + + +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 } } +}; + + + +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 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") + } + +} + + +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 expectedHeadersForTargetSheetUptoHierarchy = index !== -1 ? localizedHierarchy.slice(index) : throwError("COMMON", 400, "VALIDATION_ERROR", `${getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap)} level not present in the hierarchy`); + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + const columnFromSchemaOfTargetTemplate = await generateDynamicTargetHeaders(request, campaignObject, localizationMap); + const localizedcolumnFromSchemaOfTargetTemplate = getLocalizedHeaders(columnFromSchemaOfTargetTemplate, localizationMap) + const expectedHeadersForTargetSheet = [...expectedHeadersForTargetSheetUptoHierarchy, getLocalizedName(config?.boundary?.boundaryCode, localizationMap), ...localizedcolumnFromSchemaOfTargetTemplate]; + return expectedHeadersForTargetSheet; +} + +async function getDifferentTabGeneratedBasedOnConfig(request: any, boundaryDataGeneratedBeforeDifferentTabSeparation: any, localizationMap?: any) { + var boundaryDataGeneratedAfterDifferentTabSeparation: any = boundaryDataGeneratedBeforeDifferentTabSeparation; + const boundaryData = await getBoundaryDataAfterGeneration(boundaryDataGeneratedBeforeDifferentTabSeparation, request, localizationMap); + let differentTabsBasedOnLevel = await getBoundaryOnWhichWeSplit(request); + differentTabsBasedOnLevel = getLocalizedName(`${request?.query?.hierarchyType}_${differentTabsBasedOnLevel}`.toUpperCase(), localizationMap); + logger.info(`Boundaries are seperated based on hierarchy type ${differentTabsBasedOnLevel}`) + const isKeyOfThatTypePresent = boundaryData.some((data: any) => data.hasOwnProperty(differentTabsBasedOnLevel)); + const boundaryTypeOnWhichWeSplit = boundaryData.filter((data: any) => data[differentTabsBasedOnLevel]); + 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); + } + return boundaryDataGeneratedAfterDifferentTabSeparation; +} + +async function getBoundaryOnWhichWeSplit(request: any) { + const mdmsResponse = await getMDMSV1Data(request, config?.values?.moduleName, config?.masterNameForSplitBoundariesOn, request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId); + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const hierarchyTypeFromCampaignResponseObject = responseFromCampaignSearch?.CampaignDetails?.[0].hierarchyType; + return mdmsResponse.filter((item: any) => item.hierarchy == hierarchyTypeFromCampaignResponseObject).map((item: any) => item.splitBoundariesOn); +} + + +function checkIfSourceIsMicroplan(objectWithAdditionalDetails: any): boolean { + return objectWithAdditionalDetails?.additionalDetails?.source === 'microplan'; +} + + + + + + + +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, + checkIfSourceIsMicroplan, + getBoundaryOnWhichWeSplit +} diff --git a/health-services/project-factory/src/server/utils/db/index.ts b/health-services/project-factory/src/server/utils/db/index.ts new file mode 100644 index 00000000000..d987e3eac0d --- /dev/null +++ b/health-services/project-factory/src/server/utils/db/index.ts @@ -0,0 +1,31 @@ +import pool from "../../config/dbPoolConfig"; +import { throwError } from "../genericUtils"; +import { getFormattedStringForDebug, logger } from "../logger"; + +/** + * Executes a database query asynchronously. + * + * @param {string} query - The SQL query to execute. + * @param {any} values - The values to be used in the query. + * @returns {Promise} - A Promise resolving to the query response. + * @throws - Throws an error if there is an issue with executing the query or closing the database connection. + */ +export const executeQuery = async ( + query: string, + values: any +): Promise => { + try { + logger.info(`DB QUERY :: STATEMENT :: ${query}`); + logger.info(`DB QUERY :: VALUES :: ${values}`); + const queryResponse = await pool.query(query, values); + logger.info( + `DB QUERY :: RESPONSE :: SUCCESS :: returns ${queryResponse?.rowCount} rows.` + ); + logger.debug( `DB QUERY :: RESPONSE :: SUCCESS :: Query Response ${getFormattedStringForDebug(queryResponse?.rows)}`); + return queryResponse; + } catch (error: any) { + logger.error(`Error fetching data from the database: ${error?.message}`); + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", error?.message); + throw error; + } +}; diff --git a/health-services/project-factory/src/server/utils/excelUtils.ts b/health-services/project-factory/src/server/utils/excelUtils.ts new file mode 100644 index 00000000000..8f7a0acc614 --- /dev/null +++ b/health-services/project-factory/src/server/utils/excelUtils.ts @@ -0,0 +1,262 @@ +import * as ExcelJS from "exceljs"; +import { changeFirstRowColumnColour, throwError } from "./genericUtils"; +import { httpRequest } from "./request"; +import { logger } from "./logger"; +import config from "../config"; +/** + * Function to create a new Excel workbook using the ExcelJS library + * @returns {ExcelJS.Workbook} - A new Excel workbook object + */ +const getNewExcelWorkbook = () => { + const workbook = new ExcelJS.Workbook(); + return workbook; +}; + +// Function to retrieve workbook from Excel file URL and sheet name +const getExcelWorkbookFromFileURL = async ( + fileUrl: string, + sheetName: string +) => { + // Define headers for HTTP request + const headers = { + "Content-Type": "application/json", + Accept: "application/pdf", + }; + logger.info("loading for the file based on fileurl"); + // Make HTTP request to retrieve Excel file as arraybuffer + const responseFile = await httpRequest( + fileUrl, + null, + {}, + "get", + "arraybuffer", + headers + ); + 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.` + ); + } + + // Return the workbook + return workbook; +}; + +function updateFontNameToRoboto(worksheet: ExcelJS.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 + }; + }); + }); +} + +function formatWorksheet(worksheet: any, datas: any, headerSet: any) { + // Add empty rows after the main header + // worksheet.addRow([]); + // worksheet.addRow([]); + worksheet.addRow([]); + + // 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 + + datas.forEach((data: any) => { + const row = worksheet.addRow([data]); + row.eachCell({ includeEmpty: true }, (cell: any) => { + cell.alignment = { vertical: 'middle', horizontal: 'left', wrapText: true }; // Apply text wrapping + // Calculate the required row height based on content length + const numberOfLines = Math.ceil(data.length / maxCharactersPerLine); + row.height = numberOfLines * lineHeight; + + // Make the header text bold + if (headerSet.has(cell.value)) { + cell.font = { bold: true }; + } + }); + }); + + worksheet.getColumn(1).width = 130; + logger.info(`Freezing the whole sheet ${worksheet.name}`); + worksheet.eachRow((row: any) => { + row.eachCell((cell: any) => { + cell.protection = { locked: true }; + }); + }); + worksheet.protect('passwordhere', { selectLockedCells: true }); +} + +function performUnfreezeCells(sheet: any) { + logger.info(`Unfreezing the sheet ${sheet.name}`); + + let lastFilledColumn = 1; + sheet.getRow(1).eachCell((cell: any, colNumber: number) => { + if (cell.value !== undefined && cell.value !== null && cell.value !== '') { + lastFilledColumn = colNumber; + } + }); + + for (let row = 1; row <= parseInt(config.values.unfrozeTillRow); 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('passwordhere', { selectLockedCells: true, selectUnlockedCells: true }); +} + + +function performFreezeWholeSheet(sheet: any) { + logger.info(`Freezing the whole sheet ${sheet.name}`); + sheet.eachRow((row: any) => { + row.eachCell((cell: any) => { + cell.protection = { locked: true }; + }); + }); + sheet.protect('passwordhere', { selectLockedCells: true }); +} + +// Function to add data to the sheet +function addDataToSheet(sheet: any, sheetData: any, firstRowColor: string = '93C47D', columnWidth: number = 40, frozeCells: boolean = false, frozeWholeSheet: boolean = false) { + sheetData?.forEach((row: any, index: number) => { + const worksheetRow = sheet.addRow(row); + + if (index === 0) { + formatFirstRow(worksheetRow, sheet, firstRowColor, columnWidth, frozeCells); + } else { + formatOtherRows(worksheetRow, frozeCells); + } + }); + + finalizeSheet(sheet, frozeCells, frozeWholeSheet); +} + +// Function to format the first row +function formatFirstRow(row: any, sheet: any, firstRowColor: string, columnWidth: number, frozeCells: boolean) { + row.eachCell((cell: any, colNumber: number) => { + setFirstRowCellStyles(cell, firstRowColor, frozeCells); + adjustColumnWidth(sheet, colNumber, columnWidth); + adjustRowHeight(row, cell, columnWidth); + }); +} + +// Function to set styles for the first row's cells +function setFirstRowCellStyles(cell: any, firstRowColor: string, frozeCells: boolean) { + cell.fill = { + type: 'pattern', + pattern: 'solid', + fgColor: { argb: firstRowColor } + }; + + cell.font = { bold: true }; + + 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 }; + } + }); +} + +// Function to finalize the sheet settings +function finalizeSheet(sheet: any, frozeCells: boolean, frozeWholeSheet: boolean) { + if (frozeCells) { + performUnfreezeCells(sheet); + } + if (frozeWholeSheet) { + performFreezeWholeSheet(sheet); + } + updateFontNameToRoboto(sheet); + sheet.views = [{ state: 'frozen', ySplit: 1, zoomScale: 110 }]; +} + + + + + +function lockTargetFields(newSheet: any, columnsNotToBeFreezed: any, boundaryCodeColumnIndex: any) { + // Make every cell locked by default + newSheet.eachRow((row: any) => { + row.eachCell((cell: any) => { + cell.protection = { locked: true }; + }); + }); + + // // Get headers in the first row and filter out empty items + const headers = newSheet.getRow(1).values.filter((header: any) => header); + logger.info(`Filtered Headers in the first row : ${headers}`); + + // Unlock cells in the target columns + if (Array.isArray(columnsNotToBeFreezed) && columnsNotToBeFreezed.length > 0) { + columnsNotToBeFreezed.forEach((header) => { + 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) => { + changeFirstRowColumnColour(newSheet, 'B6D7A8', targetColumnNumber); + if (rowNumber === 1) return; + + const cell = row.getCell(targetColumnNumber); + cell.protection = { locked: false }; + }); + + } else { + console.error(`Header "${header}" not found in the first row`); + } + }); + } + + // Hide the boundary code column + if (boundaryCodeColumnIndex !== -1) { + newSheet.getColumn(boundaryCodeColumnIndex + 1).hidden = true; // Excel columns are 1-based + } + + // Protect the sheet with a password (optional) + newSheet.protect('passwordhere', { + selectLockedCells: true, + selectUnlockedCells: true, + }); +} + + +export { getNewExcelWorkbook, getExcelWorkbookFromFileURL, formatWorksheet, addDataToSheet, lockTargetFields, updateFontNameToRoboto }; diff --git a/health-services/project-factory/src/server/utils/generateUtils.ts b/health-services/project-factory/src/server/utils/generateUtils.ts new file mode 100644 index 00000000000..a8a03e65d7c --- /dev/null +++ b/health-services/project-factory/src/server/utils/generateUtils.ts @@ -0,0 +1,85 @@ +import { getLocalizedMessagesHandler, processGenerate, replicateRequest, throwError } from "./genericUtils"; +import _ from 'lodash'; +import { logger } from "./logger"; +import { getBoundarySheetData } from "../api/genericApis"; +import { getLocalisationModuleName } from "./localisationUtils"; + +// Now you can use Lodash functions with the "_" prefix, e.g., _.isEqual(), _.sortBy(), etc. +function extractProperties(obj: any) { + return { + code: obj.code || null, + includeAllChildren: obj.includeAllChildren || null, + isRoot: obj.isRoot || null + }; +} + +function areBoundariesSame(existingBoundaries: any, currentBoundaries: any) { + if (!existingBoundaries || !currentBoundaries) return false; + if (existingBoundaries.length !== currentBoundaries.length) return false; + const existingSetOfBoundaries = new Set(existingBoundaries.map((exboundary: any) => JSON.stringify(extractProperties(exboundary)))); + const currentSetOfBoundaries = new Set(currentBoundaries.map((currboundary: any) => JSON.stringify(extractProperties(currboundary)))); + return _.isEqual(existingSetOfBoundaries, currentSetOfBoundaries); +} + +async function callGenerateIfBoundariesDiffer(request: any) { + try { + const ExistingCampaignDetails = request?.body?.ExistingCampaignDetails; + if (ExistingCampaignDetails) { + if (!areBoundariesSame(ExistingCampaignDetails?.boundaries, request?.body?.CampaignDetails?.boundaries)) { + logger.info("Boundaries differ, generating new resources"); + + const newRequestBody = { + RequestInfo: request?.body?.RequestInfo, + Filters: { + boundaries: request?.body?.CampaignDetails?.boundaries + } + }; + + const { query } = request; + const params = { + tenantId: request?.body?.CampaignDetails?.tenantId, + forceUpdate: 'true', + hierarchyType: request?.body?.CampaignDetails?.hierarchyType, + campaignId: request?.body?.CampaignDetails?.id + }; + + const newParamsBoundary = { ...query, ...params, type: "boundary" }; + const newRequestBoundary = replicateRequest(request, newRequestBody, newParamsBoundary); + await callGenerate(newRequestBoundary, "boundary"); + + const newParamsFacilityWithBoundary = { ...query, ...params, type: "facilityWithBoundary" }; + const newRequestFacilityWithBoundary = replicateRequest(request, newRequestBody, newParamsFacilityWithBoundary); + await callGenerate(newRequestFacilityWithBoundary, "facilityWithBoundary"); + + const newParamsUserWithBoundary = { ...query, ...params, type: "userWithBoundary" }; + const newRequestUserWithBoundary = replicateRequest(request, newRequestBody, newParamsUserWithBoundary); + await callGenerate(newRequestUserWithBoundary, "userWithBoundary"); + } + } + } catch (error: any) { + logger.error(error); + throwError("COMMON", 400, "GENERATE_ERROR", `Error while generating user/facility/boundary: ${error.message}`); + } +} + +async function callGenerate(request: any, type: any, enableCaching = false) { + logger.info(`calling generate api for type ${type}`); + if (type === "facilityWithBoundary" || type == "userWithBoundary") { + const { hierarchyType } = request.query; + const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler( + request, + request.query.tenantId, + getLocalisationModuleName(hierarchyType) + ); + const localizationMapModule = await getLocalizedMessagesHandler(request, request.query.tenantId); + const localizationMap = { ...localizationMapHierarchy, ...localizationMapModule }; + const filteredBoundary = await getBoundarySheetData(request, localizationMap); + await processGenerate(request, enableCaching, filteredBoundary); + } else { + await processGenerate(request, enableCaching); + } +} + + + +export { callGenerateIfBoundariesDiffer, callGenerate, areBoundariesSame } diff --git a/health-services/project-factory/src/server/utils/genericUtils.ts b/health-services/project-factory/src/server/utils/genericUtils.ts new file mode 100644 index 00000000000..df6f5ec8bfb --- /dev/null +++ b/health-services/project-factory/src/server/utils/genericUtils.ts @@ -0,0 +1,1239 @@ +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/Producer"; +import { generateHierarchyList, getAllFacilities, getCampaignSearchResponse, getHierarchy } from "../api/campaignApis"; +import { getBoundarySheetData, getSheetData, createAndUploadFile, createExcelSheet, getTargetSheetData, callMdmsData, callMdmsTypeSchema } from "../api/genericApis"; +import { logger } from "./logger"; +import { 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, getLocaleFromRequestInfo, getLocalisationModuleName } from "./localisationUtils"; +import { getBoundaryColumnName, getBoundaryTabName } from "./boundaryUtils"; +import { getBoundaryDataService } from "../service/dataManageService"; +import { addDataToSheet, formatWorksheet, getNewExcelWorkbook, updateFontNameToRoboto } from "./excelUtils"; +import createAndSearch from "../config/createAndSearch"; +import { generateDynamicTargetHeaders } from "./targetUtils"; +const NodeCache = require("node-cache"); + +const updateGeneratedResourceTopic = config?.kafka?.KAFKA_UPDATE_GENERATED_RESOURCE_DETAILS_TOPIC; +const createGeneratedResourceTopic = config?.kafka?.KAFKA_CREATE_GENERATED_RESOURCE_DETAILS_TOPIC; + +/* + stdTTL: (default: 0) the standard ttl as number in seconds for every generated + cache element. 0 = unlimited + + checkperiod: (default: 600) The period in seconds, as a number, used for the automatic + delete check interval. 0 = no periodic check. + + 30 mins caching +*/ + +const appCache = new NodeCache({ stdTTL: 1800000, checkperiod: 300 }); + +/* +Send The Error Response back to client with proper response code +*/ +const throwErrorViaRequest = (message: any = "Internal Server Error") => { + if (message?.message || message?.code) { + let error: any = new Error(message?.message || message?.code); + error = Object.assign(error, { status: message?.status || 500 }); + logger.error("Error : " + error + " " + (message?.description || "")); + throw error; + } + else { + let error: any = new Error(message); + error = Object.assign(error, { status: 500 }); + logger.error("Error : " + error); + throw error; + } +}; + +function 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); +} + +const throwError = (module = "COMMON", status = 500, code = "UNKNOWN_ERROR", description: any = null) => { + const errorResult: any = getErrorCodes(module, code); + status = errorResult?.code == "UNKNOWN_ERROR" ? 500 : status; + let error: any = new Error(capitalizeFirstLetter(errorResult?.message)); + error = Object.assign(error, { status, code: errorResult?.code, description: capitalizeFirstLetter(description) }); + logger.error(error); + throw error; +}; + + +const replicateRequest = (originalRequest: Request, requestBody: any, requestQuery?: any) => { + const newRequest = { + ...originalRequest, + body: requestBody, + query: requestQuery || originalRequest.query + }; + return newRequest; +}; + + +/* +Error Object +*/ +const getErrorResponse = ( + code = "INTERNAL_SERVER_ERROR", + message = "Some Error Occured!!", + description: any = null +) => ({ + ResponseInfo: null, + Errors: [ + { + code: code, + message: message, + description: description, + params: null, + }, + ], +}); + +/* +Send The Response back to client with proper response code and response info +*/ +const sendResponse = ( + response: Response, + responseBody: any, + req: Request, + code: number = 200 +) => { + /* if (code != 304) { + appCache.set(req.headers.cachekey, { ...responseBody }); + } else { + logger.info("CACHED RESPONSE FOR :: " + req.headers.cachekey); + } + */ + logger.info("Send back the response to the client"); + response.status(code).send({ + ...getResponseInfo(code), + ...responseBody, + }); +}; + +/* +Sets the cahce response +*/ +const cacheResponse = (res: Response, key: string) => { + if (key != null) { + appCache.set(key, { ...res }); + logger.info("CACHED RESPONSE FOR :: " + key); + } +}; + +/* +gets the cahce response +*/ +const getCachedResponse = (key: string) => { + if (key != null) { + const data = appCache.get(key); + if (data) { + logger.info("CACHE STATUS :: " + JSON.stringify(appCache.getStats())); + logger.info("RETURNS THE CACHED RESPONSE FOR :: " + key); + return data; + } + } + return null; +}; + +/* +Response Object +*/ +const getResponseInfo = (code: Number) => ({ + ResponseInfo: { + apiId: "egov-bff", + ver: "0.0.1", + ts: new Date().getTime(), + status: "successful", + desc: code == 304 ? "cached-response" : "new-response", + }, +}); + +/* +Fallback Middleware function for returning 404 error for undefined paths +*/ +const invalidPathHandler = ( + request: any, + response: any, + next: NextFunction +) => { + response.status(404); + response.send(getErrorResponse("INVALID_PATH", "invalid path")); +}; + +/* +Error handling Middleware function for logging the error message +*/ +const errorLogger = ( + error: Error, + request: any, + response: any, + next: NextFunction +) => { + logger.error(error.stack); + logger.error(`error ${error.message}`); + next(error); // calling next middleware +}; + +/* +Error handling Middleware function reads the error message and sends back a response in JSON format +*/ +const errorResponder = ( + error: any, + request: any, + response: Response, + status: any = 500, + next: any = null +) => { + if (error?.status) { + status = error?.status; + } + const code = error?.code || (status === 500 ? "INTERNAL_SERVER_ERROR" : (status === 400 ? "BAD_REQUEST" : "UNKNOWN_ERROR")); + response.header("Content-Type", "application/json"); + const errorMessage = trimError(error.message || "Some Error Occurred!!"); + const errorDescription = error.description || null; + const errorResponse = getErrorResponse(code, errorMessage, errorDescription); + response.status(status).send(errorResponse); +}; + + +const trimError = (e: any) => { + if (typeof e === "string") { + e = e.trim(); + while (e.startsWith("Error:")) { + e = e.substring(6); + e = e.trim(); + } + } + return e; +} + + +async function generateActivityMessage(tenantId: any, requestBody: any, requestPayload: any, responsePayload: any, type: any, url: any, status: any) { + const activityMessage = { + id: uuidv4(), + status: status, + retryCount: 0, + tenantId: tenantId, + type: type, + url: url, + requestPayload: requestPayload, + responsePayload: responsePayload, + auditDetails: { + createdBy: requestBody?.RequestInfo?.userInfo?.uuid, + lastModifiedBy: requestBody?.RequestInfo?.userInfo?.uuid, + createdTime: Date.now(), + lastModifiedTime: Date.now() + }, + additionalDetails: {}, + resourceDetailsId: null + } + return activityMessage; +} + +/* Fetches data from the database */ +async function searchGeneratedResources(request: any) { + try { + 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); + } + + if (hierarchyType) { + queryConditions.push(`hierarchyType = $${queryValues.length + 1}`); + queryValues.push(hierarchyType); + } + 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); + } + + 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) { + 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 + } +} + +async function enrichAuditDetails(responseData: any) { + return responseData.map((item: any) => { + return { + ...item, + count: parseInt(item.count), + auditDetails: { + ...item.auditDetails, + lastModifiedTime: parseInt(item.auditDetails.lastModifiedTime), + createdTime: parseInt(item.auditDetails.createdTime) + } + }; + }); +} + +async function generateNewRequestObject(request: any) { + const { type } = request.query; + const additionalDetails = type === 'boundary' + ? { Filters: request?.body?.Filters ?? null } + : {}; + const newEntry = { + id: uuidv4(), + fileStoreid: null, + type: type, + status: generatedResourceStatuses.inprogress, + hierarchyType: request?.query?.hierarchyType, + tenantId: request?.query?.tenantId, + auditDetails: { + lastModifiedTime: Date.now(), + createdTime: Date.now(), + createdBy: request?.body?.RequestInfo?.userInfo.uuid, + lastModifiedBy: request?.body?.RequestInfo?.userInfo.uuid, + }, + additionalDetails: additionalDetails, + count: null, + campaignId: request?.query?.campaignId + }; + return [newEntry]; +} +async function updateExistingResourceExpired(modifiedResponse: any[], request: any) { + return modifiedResponse.map((item: any) => { + const newItem = { ...item }; + newItem.status = generatedResourceStatuses.expired; + newItem.auditDetails.lastModifiedTime = Date.now(); + newItem.auditDetails.lastModifiedBy = request?.body?.RequestInfo?.userInfo?.uuid; + return newItem; + }); +} +async function getFinalUpdatedResponse(result: any, responseData: any, request: any) { + return responseData.map((item: any) => { + return { + ...item, + tenantId: request?.query?.tenantId, + count: parseInt(request?.body?.generatedResourceCount || null), + auditDetails: { + ...item.auditDetails, + lastModifiedTime: Date.now(), + createdTime: Date.now(), + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid + }, + fileStoreid: result?.[0]?.fileStoreId, + status: resourceDataStatuses.completed + }; + }); +} + + + +async function fullProcessFlowForNewEntry(newEntryResponse: any, generatedResource: any, request: any, 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}`) + await produceModifiedMessages(generatedResource, createGeneratedResourceTopic); + const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler(request, request?.query?.tenantId, getLocalisationModuleName(hierarchyType)); + const localizationMapModule = await getLocalizedMessagesHandler(request, request?.query?.tenantId); + const localizationMap = { ...localizationMapHierarchy, ...localizationMapModule }; + if (type === 'boundary') { + // get boundary data from boundary relationship search api + logger.info("Generating Boundary Data") + const boundaryDataSheetGeneratedBeforeDifferentTabSeparation = await getBoundaryDataService(request, enableCaching); + logger.info(`Boundary data generated successfully: ${JSON.stringify(boundaryDataSheetGeneratedBeforeDifferentTabSeparation)}`); + // get boundary sheet data after being generated + logger.info("generating different tabs logic ") + const boundaryDataSheetGeneratedAfterDifferentTabSeparation = await getDifferentTabGeneratedBasedOnConfig(request, boundaryDataSheetGeneratedBeforeDifferentTabSeparation, localizationMap) + 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 + await produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); + request.body.generatedResource = finalResponse; + } + else if (type == "facilityWithBoundary" || type == 'userWithBoundary') { + await processGenerateRequest(request, localizationMap, filteredBoundary); + const finalResponse = await getFinalUpdatedResponse(request?.body?.fileDetails, newEntryResponse, request); + const generatedResourceNew: any = { generatedResource: finalResponse } + await produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); + request.body.generatedResource = finalResponse; + } + } catch (error: any) { + console.log(error) + await handleGenerateError(newEntryResponse, generatedResource, error); + } +} + +function generateAuditDetails(request: any) { + const createdBy = request?.body?.RequestInfo?.userInfo?.uuid; + const lastModifiedBy = request?.body?.RequestInfo?.userInfo?.uuid; + const auditDetails = { + createdBy: createdBy, + lastModifiedBy: lastModifiedBy, + createdTime: Date.now(), + lastModifiedTime: Date.now() + } + return auditDetails; +} + + + +function sortCampaignDetails(campaignDetails: any) { + campaignDetails.sort((a: any, b: any) => { + // If a is a child of b, a should come after b + if (a.parentBoundaryCode === b.boundaryCode) return 1; + // If b is a child of a, a should come before b + if (a.boundaryCode === b.parentBoundaryCode) return -1; + // Otherwise, maintain the order + return 0; + }); + return campaignDetails; +} +// Function to correct the totals and target values of parents +function correctParentValues(campaignDetails: any) { + // Create a map to store parent-child relationships and their totals/targets + const parentMap: any = {}; + campaignDetails.forEach((detail: any) => { + if (!detail.parentBoundaryCode) return; // Skip if it's not a child + if (!parentMap[detail.parentBoundaryCode]) { + parentMap[detail.parentBoundaryCode] = { total: 0, target: 0 }; + } + parentMap[detail.parentBoundaryCode].total += detail.targets[0].total; + parentMap[detail.parentBoundaryCode].target += detail.targets[0].target; + }); + + // Update parent values with the calculated totals and targets + campaignDetails.forEach((detail: any) => { + if (!detail.parentBoundaryCode) return; // Skip if it's not a child + const parent = parentMap[detail.parentBoundaryCode]; + const target = detail.targets[0]; + target.total = parent.total; + target.target = parent.target; + }); + + return campaignDetails; +} + +function setDropdownFromSchema(request: any, schema: any, localizationMap?: { [key: string]: string }) { + const dropdowns = Object.entries(schema.properties) + .filter(([key, value]: any) => Array.isArray(value.enum) && value.enum.length > 0) + .reduce((result: any, [key, value]: any) => { + // Transform the key using localisedValue function + const newKey: any = getLocalizedName(key, localizationMap); + result[newKey] = value.enum; + return result; + }, {}); + logger.info(`dropdowns to set ${JSON.stringify(dropdowns)}`) + request.body.dropdowns = dropdowns; +} + +async function createFacilitySheet(request: any, allFacilities: any[], localizationMap?: { [key: string]: string }) { + const tenantId = request?.query?.tenantId; + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const isSourceMicroplan = checkIfSourceIsMicroplan(responseFromCampaignSearch?.CampaignDetails?.[0]); + let schema; + if (isSourceMicroplan) { + schema = await callMdmsTypeSchema(request, tenantId, "facility", "microplan"); + } else { + schema = await callMdmsTypeSchema(request, tenantId, "facility", "all"); + } + const keys = schema?.columns; + setDropdownFromSchema(request, schema, localizationMap); + const headers = ["HCM_ADMIN_CONSOLE_FACILITY_CODE", ...keys] + let localizedHeaders; + if (isSourceMicroplan) { + localizedHeaders = getLocalizedHeadersForMicroplan(responseFromCampaignSearch, headers, localizationMap); + + } + else { + localizedHeaders = getLocalizedHeaders(headers, localizationMap); + } + const facilities = allFacilities.map((facility: any) => { + return [ + facility?.id, + facility?.name, + facility?.usage, + facility?.isPermanent ? "Permanent" : "Temporary", + facility?.storageCapacity, + "" + ] + }) + logger.info("facilities generation done "); + logger.debug(`facility response ${JSON.stringify(facilities)}`) + const facilitySheetData: any = await createExcelSheet(facilities, localizedHeaders); + return facilitySheetData; +} + + + +function setAndFormatHeaders(worksheet: any, mainHeader: any, headerSet: any) { + + // Ensure mainHeader is an array + if (!Array.isArray(mainHeader)) { + mainHeader = [mainHeader]; + } + // headerSet.add(mainHeader) + const headerRow = worksheet.addRow(mainHeader); + + // Color the header cell + headerRow.eachCell((cell: any) => { + 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 }; + }); +} + +async function createReadMeSheet(request: any, workbook: any, mainHeader: any, localizationMap = {}) { + const readMeConfig = await getReadMeConfig(request); + const headerSet = new Set(); + + + 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, ""]; + }); + + // Create the worksheet and add the main header + const worksheet = workbook.addWorksheet(getLocalizedName("HCM_README_SHEETNAME", localizationMap)); + + setAndFormatHeaders(worksheet, mainHeader, headerSet); + + formatWorksheet(worksheet, datas, headerSet); + + updateFontNameToRoboto(worksheet); + + return worksheet; +} + + +function createBoundaryDataMainSheet(request: any, boundaryData: any, differentTabsBasedOnLevel: any, hierarchy: any, localizationMap?: any) { + const uniqueDistrictsForMainSheet: string[] = []; + const districtLevelRowBoundaryCodeMap = new Map(); + const mainSheetData: any[] = []; + const headersForMainSheet = differentTabsBasedOnLevel ? hierarchy.slice(0, hierarchy.indexOf(differentTabsBasedOnLevel) + 1) : []; + const localizedHeadersForMainSheet = getLocalizedHeaders(headersForMainSheet, localizationMap); + const localizedBoundaryCode = getLocalizedName(getBoundaryColumnName(), localizationMap); + localizedHeadersForMainSheet.push(localizedBoundaryCode); + mainSheetData.push([...localizedHeadersForMainSheet]); + for (const data of boundaryData) { + const modifiedData = modifyDataBasedOnDifferentTab(data, differentTabsBasedOnLevel, localizedHeadersForMainSheet, localizationMap); + const rowData = Object.values(modifiedData); + const districtIndex = modifiedData[differentTabsBasedOnLevel] !== '' ? rowData.indexOf(data[differentTabsBasedOnLevel]) : -1; + if (districtIndex == -1) { + mainSheetData.push(rowData); + } else { + const districtLevelRow = rowData.slice(0, districtIndex + 1); + if (!uniqueDistrictsForMainSheet.includes(districtLevelRow.join('#'))) { + uniqueDistrictsForMainSheet.push(districtLevelRow.join('#')); + districtLevelRowBoundaryCodeMap.set(districtLevelRow.join('#'), data[getLocalizedName(getBoundaryColumnName(), localizationMap)]); + mainSheetData.push(rowData); + } + } + } + return [mainSheetData, uniqueDistrictsForMainSheet, districtLevelRowBoundaryCodeMap] +} + + +function getLocalizedHeaders(headers: any, localizationMap?: { [key: string]: string }) { + const messages = headers.map((header: any) => (localizationMap ? localizationMap[header] || header : header)); + 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) { + const { RequestInfo } = request?.body; + const query = { + "tenantId": tenantId, + "locale": getLocaleFromRequest(request), + "module": config.localisation.localizationModule + }; + const updatedRequest = { ...request }; + updatedRequest.body = { RequestInfo }; + updatedRequest.query = query; + return updatedRequest; +} + +async function getReadMeConfig(request: any) { + const mdmsResponse = await callMdmsData(request, "HCM-ADMIN-CONSOLE", "ReadMeConfig", request?.query?.tenantId); + if (mdmsResponse?.MdmsRes?.["HCM-ADMIN-CONSOLE"]?.ReadMeConfig) { + const readMeConfigsArray = mdmsResponse?.MdmsRes?.["HCM-ADMIN-CONSOLE"]?.ReadMeConfig + for (const readMeConfig of readMeConfigsArray) { + if (readMeConfig?.type == request?.query?.type) { + return readMeConfig + } + } + throwError("MDMS", 500, "INVALID_README_CONFIG", `Readme config for type ${request?.query?.type} not found.`); + return {} + } + else { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", `Some error occured during readme config mdms search.`); + return {}; + } +} + + +function changeFirstRowColumnColour(facilitySheet: any, color: any, columnNumber = 1) { + // Color the first column header of the facility sheet orange + const headerRow = facilitySheet.getRow(1); // Assuming the first row is the header + const firstHeaderCell = headerRow.getCell(columnNumber); + firstHeaderCell.fill = { + type: 'pattern', + pattern: 'solid', + fgColor: { argb: color } + }; +} + +function hideUniqueIdentifierColumn(sheet: any, column: any) { + if (column) { + sheet.getColumn(column).hidden = true + } +} + + +async function createFacilityAndBoundaryFile(facilitySheetData: any, boundarySheetData: any, request: any, localizationMap?: any) { + const workbook = getNewExcelWorkbook(); + + // Add facility sheet to the workbook + const localizedFacilityTab = getLocalizedName(config?.facility?.facilityTab, localizationMap); + const type = request?.query?.type; + const headingInSheet = headingMapping?.[type]; + const localizedHeading = getLocalizedName(headingInSheet, localizationMap); + + // Create and add ReadMe sheet + await createReadMeSheet(request, workbook, localizedHeading, localizationMap); + + // Add facility sheet data + const facilitySheet = workbook.addWorksheet(localizedFacilityTab); + addDataToSheet(facilitySheet, facilitySheetData, undefined, undefined, true); + hideUniqueIdentifierColumn(facilitySheet, createAndSearch?.["facility"]?.uniqueIdentifierColumn); + changeFirstRowColumnColour(facilitySheet, 'E06666'); + await handledropdownthings(facilitySheet, request.body?.dropdowns); + + // Add boundary sheet to the workbook + const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap); + const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); + addDataToSheet(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(facilitySheet: any, dropdowns: any) { + let dropdownColumnIndex = -1; + if (dropdowns) { + for (const key of Object.keys(dropdowns)) { + if (dropdowns[key]) { + // Iterate through each row to find the column index of "Boundary Code (Mandatory)" + await facilitySheet.eachRow({ includeEmpty: true }, (row: any) => { + row.eachCell({ includeEmpty: true }, (cell: any, colNumber: any) => { + if (cell.value === key) { + dropdownColumnIndex = colNumber; + } + }); + }); + + // If dropdown column index is found, set multi-select dropdown for subsequent rows + if (dropdownColumnIndex !== -1) { + facilitySheet.getColumn(dropdownColumnIndex).eachCell({ includeEmpty: true }, (cell: any, rowNumber: any) => { + if (rowNumber > 1) { + // Set dropdown list with no typing allowed + cell.dataValidation = { + type: 'list', + formulae: [`"${dropdowns[key].join(',')}"`], + showDropDown: true, // Ensures dropdown is visible + error: 'Please select a value from the dropdown list.', + errorStyle: 'stop', // Prevents any input not in the list + showErrorMessage: true, // Ensures error message is shown + errorTitle: 'Invalid Entry' + }; + } + }); + } + } + } + } +} + + + + + + +async function createUserAndBoundaryFile(userSheetData: any, boundarySheetData: any, request: any, localizationMap?: { [key: string]: string }) { + const workbook = getNewExcelWorkbook(); + const localizedUserTab = getLocalizedName(config?.user?.userTab, localizationMap); + const type = request?.query?.type; + const headingInSheet = headingMapping?.[type] + const localisedHeading = getLocalizedName(headingInSheet, localizationMap) + await createReadMeSheet(request, workbook, localisedHeading, localizationMap); + + const userSheet = workbook.addWorksheet(localizedUserTab); + addDataToSheet(userSheet, userSheetData, undefined, undefined, true); + await handledropdownthings(userSheet, request.body?.dropdowns); + // Add boundary sheet to the workbook + const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap) + const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); + addDataToSheet(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 }, filteredBoundary?: any) { + // Get facility and boundary data + logger.info("Generating facilities started"); + const allFacilities = await getAllFacilities(tenantId, request.body); + request.body.generatedResourceCount = allFacilities?.length; + logger.info(`Facilities generation completed and found ${allFacilities?.length} facilities`); + const facilitySheetData: any = await createFacilitySheet(request, allFacilities, localizationMap); + // request.body.Filters = { tenantId: tenantId, hierarchyType: request?.query?.hierarchyType, includeChildren: true } + if (filteredBoundary && filteredBoundary.length > 0) { + await createFacilityAndBoundaryFile(facilitySheetData, filteredBoundary, request, localizationMap); + } + else { + const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); + await createFacilityAndBoundaryFile(facilitySheetData, boundarySheetData, request, localizationMap); + } +} +async function generateUserAndBoundarySheet(request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any) { + const userData: any[] = []; + const tenantId = request?.query?.tenantId; + const schema = await callMdmsTypeSchema(request, tenantId, "user"); + setDropdownFromSchema(request, schema, localizationMap); + const headers = schema?.columns; + const localizedHeaders = getLocalizedHeaders(headers, localizationMap); + // const localizedUserTab = getLocalizedName(config?.user?.userTab, localizationMap); + logger.info("Generated an empty user template"); + const userSheetData = await createExcelSheet(userData, localizedHeaders); + if (filteredBoundary && filteredBoundary.length > 0) { + await createUserAndBoundaryFile(userSheetData, filteredBoundary, request, localizationMap); + } + else { + const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); + await createUserAndBoundaryFile(userSheetData, boundarySheetData, request, localizationMap); + } +} +async function processGenerateRequest(request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any) { + const { type, tenantId } = request.query + if (type == "facilityWithBoundary") { + await generateFacilityAndBoundarySheet(String(tenantId), request, localizationMap, filteredBoundary); + } + if (type == "userWithBoundary") { + await generateUserAndBoundarySheet(request, localizationMap, filteredBoundary); + } +} + +async function processGenerateForNew(request: any, generatedResource: any, newEntryResponse: any, enableCaching = false, filteredBoundary?: any) { + request.body.generatedResource = newEntryResponse; + await fullProcessFlowForNewEntry(newEntryResponse, generatedResource, request, enableCaching, filteredBoundary); + return request.body.generatedResource; +} + +async function handleGenerateError(newEntryResponse: any, generatedResource: any, error: any) { + newEntryResponse.map((item: any) => { + item.status = generatedResourceStatuses.failed, item.additionalDetails = { + ...item.additionalDetails, error: { + status: error.status, + code: error.code, + description: error.description, + message: error.message + } || String(error) + } + }) + generatedResource = { generatedResource: newEntryResponse }; + logger.error(String(error)); + await produceModifiedMessages(generatedResource, updateGeneratedResourceTopic); +} + +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 + await produceModifiedMessages(generatedResource, updateGeneratedResourceTopic); + request.body.generatedResource = oldEntryResponse; + } + if (responseData.length === 0 || forceUpdateBool) { + processGenerateForNew(request, generatedResource, newEntryResponse, enableCaching, filteredBoundary) + } + else { + request.body.generatedResource = responseData + } +} +/* + +*/ +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 + const modifiedResponse = await enrichAuditDetails(responseData); + // generate new random id and make filestore id null + const newEntryResponse = await generateNewRequestObject(request); + // make old data status as expired + const oldEntryResponse = await updateExistingResourceExpired(modifiedResponse, request); + // generate data + await updateAndPersistGenerateRequest(newEntryResponse, oldEntryResponse, responseData, request, enableCaching, filteredBoundary); +} +/* +TODO add comments @nitish-egov + +*/ +async function enrichResourceDetails(request: any) { + request.body.ResourceDetails.id = uuidv4(); + request.body.ResourceDetails.processedFileStoreId = null; + if (request?.body?.ResourceDetails?.action == "create") { + request.body.ResourceDetails.status = resourceDataStatuses.accepted + } + else { + request.body.ResourceDetails.status = resourceDataStatuses.started + } + request.body.ResourceDetails.auditDetails = { + createdBy: request?.body?.RequestInfo?.userInfo?.uuid, + createdTime: Date.now(), + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now() + } + if (request.body.ResourceDetails.type === 'boundary') { + request.body.ResourceDetails.campaignId = null; + } + const persistMessage: any = { ResourceDetails: request.body.ResourceDetails }; + await produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_CREATE_RESOURCE_DETAILS_TOPIC); +} + +function getFacilityIds(data: any) { + return data.map((obj: any) => obj["id"]) +} + +function matchData(request: any, datas: any, searchedDatas: any, createAndSearchConfig: any) { + const uid = createAndSearchConfig.uniqueIdentifier; + const errors = [] + for (const data of datas) { + const searchData = searchedDatas.find((searchedData: any) => searchedData[uid] == data[uid]); + + if (!searchData) { + errors.push({ status: "INVALID", rowNumber: data["!row#number!"], errorDetails: `Data with ${uid} ${data[uid]} not found in searched data.` }) + } + else if (createAndSearchConfig?.matchEachKey) { + const keys = Object.keys(data); + var errorString = ""; + var errorFound = false; + for (const key of keys) { + if (searchData.hasOwnProperty(key) && searchData[key] !== data[key] && key != "!row#number!") { + errorString += `Value mismatch for key "${key}. Expected: "${data[key]}", Found: "${searchData[key]}"` + errorFound = true; + } + } + if (errorFound) { + errors.push({ status: "MISMATCHING", rowNumber: data["!row#number!"], errorDetails: errorString }) + } + else { + errors.push({ status: "VALID", rowNumber: data["!row#number!"], errorDetails: "" }) + } + } + else { + errors.push({ status: "VALID", rowNumber: data["!row#number!"], errorDetails: "" }) + } + } + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; +} + +function modifyBoundaryData(boundaryData: any[], localizationMap?: any) { + // Initialize arrays to store data + const withBoundaryCode: { key: string, value: string }[][] = []; + const withoutBoundaryCode: { key: string, value: string }[][] = []; + + // Get the key for the boundary code + const boundaryCodeKey = getLocalizedName(config?.boundary?.boundaryCode, localizationMap); + + // Process each object in boundaryData + boundaryData.forEach((obj: any) => { + // Convert object entries to an array of {key, value} objects + const row: any = Object.entries(obj) + .filter(([key, value]: [string, any]) => value !== null && value !== undefined) // Filter out null or undefined values + .map(([key, value]: [string, any]) => { + // Check if the current key is the "Boundary Code" key + if (key === boundaryCodeKey) { + // Keep the "Boundary Code" value as is without transformation + return { key, value: value.toString() }; + } else { + // Transform other values + return { key, value: value.toString().replace(/_/g, ' ').trim() }; + } + }); + + // Determine whether the object has a boundary code property + const hasBoundaryCode = obj.hasOwnProperty(boundaryCodeKey); + + // Push the row to the appropriate array based on whether it has a boundary code property + if (hasBoundaryCode) { + withBoundaryCode.push(row); + } else { + withoutBoundaryCode.push(row); + } + }); + + // Return the arrays + return [withBoundaryCode, withoutBoundaryCode]; +} + + +async function getDataFromSheet(request: any, fileStoreId: any, tenantId: any, createAndSearchConfig: any, optionalSheetName?: any, localizationMap?: { [key: string]: string }) { + const type = request?.body?.ResourceDetails?.type; + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: tenantId, fileStoreIds: fileStoreId }, "get"); + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 500, "DOWNLOAD_URL_NOT_FOUND"); + } + if (type == 'boundaryWithTarget') { + return await getTargetSheetData(fileResponse?.fileStoreIds?.[0]?.url, true, true, localizationMap); + } + return await getSheetData(fileResponse?.fileStoreIds?.[0]?.url, createAndSearchConfig?.parseArrayConfig?.sheetName || optionalSheetName, true, createAndSearchConfig, localizationMap) +} + +async function getBoundaryRelationshipData(request: any, params: any) { + logger.info("Boundary relationship search initiated") + const url = `${config.host.boundaryHost}${config.paths.boundaryRelationship}`; + const header = { + ...defaultheader, + 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") + return boundaryRelationshipResponse?.TenantBoundary?.[0]?.boundary; +} + +async function getDataSheetReady(boundaryData: any, request: any, localizationMap?: { [key: string]: string }) { + const type = request?.query?.type; + const boundaryType = boundaryData?.[0].boundaryType; + const boundaryList = generateHierarchyList(boundaryData) + if (!Array.isArray(boundaryList) || boundaryList.length === 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary list is empty or not an array."); + } + + const hierarchy = await getHierarchy(request, request?.query?.tenantId, request?.query?.hierarchyType); + const startIndex = boundaryType ? hierarchy.indexOf(boundaryType) : -1; + const reducedHierarchy = startIndex !== -1 ? hierarchy.slice(startIndex) : hierarchy; + const modifiedReducedHierarchy = reducedHierarchy.map(ele => `${request?.query?.hierarchyType}_${ele}`.toUpperCase()) + // get Campaign Details from Campaign Search Api + var configurableColumnHeadersBasedOnCampaignType: any[] = [] + if (type == "boundary") { + configurableColumnHeadersBasedOnCampaignType = await getConfigurableColumnHeadersBasedOnCampaignType(request, localizationMap); + } + + const headers = (type !== "facilityWithBoundary" && type !== "userWithBoundary") + ? [ + ...modifiedReducedHierarchy, + ...configurableColumnHeadersBasedOnCampaignType + ] + : [ + ...modifiedReducedHierarchy, + getBoundaryColumnName() + ]; + const localizedHeaders = getLocalizedHeaders(headers, localizationMap); + const data = boundaryList.map(boundary => { + const boundaryParts = boundary.split(','); + const boundaryCode = boundaryParts[boundaryParts.length - 1]; + const rowData = boundaryParts.concat(Array(Math.max(0, reducedHierarchy.length - boundaryParts.length)).fill('')); + // localize the boundary codes + const mappedRowData = rowData.map((cell: any, index: number) => + index === reducedHierarchy.length ? '' : cell !== '' ? getLocalizedName(cell, localizationMap) : '' + ); + const boundaryCodeIndex = reducedHierarchy.length; + mappedRowData[boundaryCodeIndex] = boundaryCode; + return mappedRowData; + }); + const sheetRowCount = data.length; + if (type != "facilityWithBoundary") { + request.body.generatedResourceCount = sheetRowCount; + } + return await createExcelSheet(data, localizedHeaders); +} + +function modifyTargetData(data: any) { + const dataArray: any[] = []; + Object.keys(data).forEach(key => { + data[key].forEach((item: any) => { + dataArray.push(item); + }); + }); + return dataArray; +} + +function calculateKeyIndex(obj: any, hierachy: any[], localizationMap?: any) { + const keys = Object.keys(obj); + const localizedBoundaryCode = getLocalizedName(getBoundaryColumnName(), localizationMap) + const boundaryCodeIndex = keys.indexOf(localizedBoundaryCode); + const keyBeforeBoundaryCode = keys[boundaryCodeIndex - 1]; + return hierachy.indexOf(keyBeforeBoundaryCode); +} + +function modifyDataBasedOnDifferentTab(boundaryData: any, differentTabsBasedOnLevel: any, localizedHeadersForMainSheet: any, localizationMap?: any) { + const newData: any = {}; + + for (const key of localizedHeadersForMainSheet) { + newData[key] = boundaryData[key] || ''; + if (key === differentTabsBasedOnLevel) break; + } + + const localizedBoundaryCode = getLocalizedName(getBoundaryColumnName(), localizationMap); + newData[localizedBoundaryCode] = boundaryData[localizedBoundaryCode] || ''; + + return newData; +} + + +async function getLocalizedMessagesHandler(request: any, tenantId: any, module = config.localisation.localizationModule) { + const localisationcontroller = Localisation.getInstance(); + const locale = getLocaleFromRequest(request); + const localizationResponse = await localisationcontroller.getLocalisedData(module, locale, tenantId); + return localizationResponse; +} + +async function 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 }) { + const translatedSchema = { + ...schema, + properties: Object.entries(schema?.properties || {}).reduce((acc, [key, value]) => { + const localizedMessage = getLocalizedName(key, localizationMap); + acc[localizedMessage] = value; + return acc; + }, {} as { [key: string]: any }), // Initialize with the correct type + required: (schema?.required || []).map((key: string) => getLocalizedName(key, localizationMap)), + unique: (schema?.unique || []).map((key: string) => getLocalizedName(key, localizationMap)) + }; + + return translatedSchema; +} + + +function findMapValue(map: Map, key: any): any | null { + let foundValue = null; + map.forEach((value, mapKey) => { + if (mapKey.key === key.key && mapKey.value === key.value) { + foundValue = value; + } + }); + return foundValue; +} + +function getDifferentDistrictTabs(boundaryData: any, differentTabsBasedOnLevel: any) { + const uniqueDistrictsForMainSheet: string[] = []; + const differentDistrictTabs: any[] = []; + for (const data of boundaryData) { + const rowData = Object.values(data); + const districtValue = data[differentTabsBasedOnLevel]; + const districtIndex = districtValue !== '' ? rowData.indexOf(districtValue) : -1; + // 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('#'); + + if (!uniqueDistrictsForMainSheet.includes(districtKey)) { + uniqueDistrictsForMainSheet.push(districtKey); + } + } + } + for (const uniqueData of uniqueDistrictsForMainSheet) { + differentDistrictTabs.push(uniqueData.slice(uniqueData.lastIndexOf('#') + 1)); + } + return differentDistrictTabs; +} + + +async function getConfigurableColumnHeadersFromSchemaForTargetSheet(request: any, hierarchy: any, boundaryData: any, differentTabsBasedOnLevel: any, campaignObject: any, localizationMap?: any) { + const districtIndex = hierarchy.indexOf(differentTabsBasedOnLevel); + 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, getLocalizedName(config?.boundary?.boundaryCode, localizationMap), ...localizedHeadersAfterHierarchy] + return getLocalizedHeaders(headers, localizationMap); +} + + +async function getMdmsDataBasedOnCampaignType(request: any, localizationMap?: any) { + 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 mdmsResponse = await callMdmsTypeSchema(request, request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, request?.query?.type || request?.body?.ResourceDetails?.type, campaignType) + return mdmsResponse; +} + + +function appendProjectTypeToCapacity(schema: any, projectType: string): any { + const updatedSchema = JSON.parse(JSON.stringify(schema)); // Deep clone the schema + + const capacityKey = 'HCM_ADMIN_CONSOLE_FACILITY_CAPACITY_MICROPLAN'; + const newCapacityKey = `${capacityKey}_${projectType}`; + + // Update properties + if (updatedSchema.properties[capacityKey]) { + updatedSchema.properties[newCapacityKey] = { + ...updatedSchema.properties[capacityKey], + name: `${updatedSchema.properties[capacityKey].name}_${projectType}` + }; + delete updatedSchema.properties[capacityKey]; + } + + // Update required + updatedSchema.required = updatedSchema.required.map((item: string) => + item === capacityKey ? newCapacityKey : item + ); + + // Update columns + updatedSchema.columns = updatedSchema.columns.map((item: string) => + item === capacityKey ? newCapacityKey : item + ); + + // Update unique + updatedSchema.unique = updatedSchema.unique.map((item: string) => + item === capacityKey ? newCapacityKey : item + ); + + // Update errorMessage + if (updatedSchema.errorMessage[capacityKey]) { + updatedSchema.errorMessage[newCapacityKey] = updatedSchema.errorMessage[capacityKey]; + delete updatedSchema.errorMessage[capacityKey]; + } + + // Update columnsNotToBeFreezed + updatedSchema.columnsNotToBeFreezed = updatedSchema.columnsNotToBeFreezed.map((item: string) => + item === capacityKey ? newCapacityKey : item + ); + + return updatedSchema; +} + + +export { + errorResponder, + errorLogger, + invalidPathHandler, + getResponseInfo, + throwError, + throwErrorViaRequest, + sendResponse, + appCache, + cacheResponse, + getCachedResponse, + generateAuditDetails, + generateActivityMessage, + searchGeneratedResources, + generateNewRequestObject, + updateExistingResourceExpired, + getFinalUpdatedResponse, + fullProcessFlowForNewEntry, + correctParentValues, + sortCampaignDetails, + processGenerateRequest, + processGenerate, + getFacilityIds, + getDataFromSheet, + matchData, + enrichResourceDetails, + modifyBoundaryData, + getBoundaryRelationshipData, + getDataSheetReady, + modifyTargetData, + calculateKeyIndex, + modifyDataBasedOnDifferentTab, + modifyRequestForLocalisation, + translateSchema, + getLocalizedMessagesHandler, + getLocalizedHeaders, + createReadMeSheet, + findMapValue, + replicateRequest, + getDifferentDistrictTabs, + addDataToSheet, + changeFirstRowColumnColour, + getConfigurableColumnHeadersFromSchemaForTargetSheet, + createBoundaryDataMainSheet, + getMdmsDataBasedOnCampaignType, + shutdownGracefully, + appendProjectTypeToCapacity, + getLocalizedMessagesHandlerViaRequestInfo +}; + + diff --git a/health-services/project-factory/src/server/utils/localisationUtils.ts b/health-services/project-factory/src/server/utils/localisationUtils.ts new file mode 100644 index 00000000000..3d5585947ef --- /dev/null +++ b/health-services/project-factory/src/server/utils/localisationUtils.ts @@ -0,0 +1,46 @@ +import config from "../config/index"; + +// Function to extract locale from request object +export const getLocaleFromRequest = (request: any) => { + // Extract msgId from request body + const msgId = request?.body?.RequestInfo?.msgId; + // Split msgId by '|' delimiter and get the second part (index 1) + // If splitting fails or no second part is found, use default locale from config + return msgId?.split("|")?.[1] || config?.localisation?.defaultLocale; +}; + +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 +export const getLocalisationModuleName = (hierarchyType: any) => { + // Construct module name using boundary prefix from config and hierarchy type + // Convert module name to lowercase + return `${config.localisation.boundaryPrefix}-${getTransformedLocale(hierarchyType)}`?.toLowerCase(); +}; + +/** + * Transforms a label into a formatted locale string. + * @param label - The label to be transformed. + * @returns The transformed locale string. + */ +export const getTransformedLocale = (label: string) => { + // Trim leading and trailing whitespace from the label + label = label?.trim(); + // If label is not empty, convert to uppercase and replace special characters with underscores + return label && label.toUpperCase().replace(/[.:-\s\/]/g, "_"); +}; + + +export const convertLocalisationResponseToMap = (messages: any = []) => { + const localizationMap: any = {}; + messages.forEach((message: any) => { + localizationMap[message.code] = message.message; + }); + return localizationMap; +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/utils/logger/index.ts b/health-services/project-factory/src/server/utils/logger/index.ts new file mode 100644 index 00000000000..f2cad55890b --- /dev/null +++ b/health-services/project-factory/src/server/utils/logger/index.ts @@ -0,0 +1,32 @@ +import { createLogger, format, transports } from "winston"; // Importing necessary modules from Winston library +import config from "../../config"; + +// Custom log format for Winston logger +const myFormat = format.printf(({ level, message, label, timestamp }) => { + return `${timestamp} [${label}] [${level}]: ${message}`; // Custom log message format +}); + +// Creating a logger instance with specified format and transports +const logger = createLogger({ + level: config.app.logLevel, // Set the minimum level to log, in this case, DEBUG + format: format.combine( + // Combining different log formats + format.label({ label: "BFF" }), // Adding label to logs + format.timestamp({ format: " YYYY-MM-DD HH:mm:ss.SSSZZ " }), // Adding timestamp to logs + format.simple(), // Simplifying log format + format.colorize(), // Adding color to logs for console output + myFormat // Using custom log format defined above + ), + transports: [new transports.Console()], // Using Console transport for logging +}); + +// Exporting the logger instance for external use +export { logger }; + +const DEFAULT_LOG_MESSAGE_COUNT = config.app.debugLogCharLimit; + +export const getFormattedStringForDebug = (obj: any) => { + const convertedMessage=JSON.stringify(obj); + return convertedMessage?.slice(0, DEFAULT_LOG_MESSAGE_COUNT) + + (convertedMessage?.length > DEFAULT_LOG_MESSAGE_COUNT ? "\n ---more" : ""); +} diff --git a/health-services/project-factory/src/server/utils/middlewares/asyncMiddleware.ts b/health-services/project-factory/src/server/utils/middlewares/asyncMiddleware.ts new file mode 100644 index 00000000000..12cb36c6516 --- /dev/null +++ b/health-services/project-factory/src/server/utils/middlewares/asyncMiddleware.ts @@ -0,0 +1,11 @@ +import { NextFunction, Request, Response } from "express"; // Importing necessary modules from Express + +// Defining a middleware function that wraps async route handlers +const asyncMiddleware = (fn: (req: Request, res: Response, next: NextFunction) => any) => + (req: Request, res: Response, next: NextFunction) => { + // Wrapping the asynchronous route handler in a Promise to handle errors + Promise.resolve(fn(req, res, next)) + .catch(next); // Catching any errors and passing them to the error handling middleware + }; + +export default asyncMiddleware; // Exporting the async middleware function for use in Express routes diff --git a/health-services/project-factory/src/server/utils/middlewares/cacheMiddleware.ts b/health-services/project-factory/src/server/utils/middlewares/cacheMiddleware.ts new file mode 100644 index 00000000000..192298615cd --- /dev/null +++ b/health-services/project-factory/src/server/utils/middlewares/cacheMiddleware.ts @@ -0,0 +1,31 @@ +// Importing necessary modules from genericUtils +import { errorResponder, appCache } from "../genericUtils"; + +// Importing necessary modules from Express +import { NextFunction, Request, Response } from "express"; + +// Variable to indicate whether caching is enabled or not +const cacheEnabled = false; + +// Middleware function to handle caching +const cacheMiddleware = (req: Request, res: Response, next: NextFunction) => { + try { + // Attempt to retrieve data from cache based on cache key in request headers + const cacheData = appCache.get(req.headers.cachekey); + + // Check if cache data exists and caching is enabled + if (cacheData && cacheEnabled) { + // If cache data exists and caching is enabled, send the cached data as response + res.send(cacheData); + } else { + // If cache data doesn't exist or caching is disabled, proceed to the next middleware/route handler + next(); + } + } catch (error) { + // If an error occurs during caching process, handle the error using errorResponder function + errorResponder(error, req, res, next); + } +}; + +// Exporting the cacheMiddleware function for use in Express middleware chain +export default cacheMiddleware; diff --git a/health-services/project-factory/src/server/utils/middlewares/index.ts b/health-services/project-factory/src/server/utils/middlewares/index.ts new file mode 100644 index 00000000000..8789bc0ef27 --- /dev/null +++ b/health-services/project-factory/src/server/utils/middlewares/index.ts @@ -0,0 +1,9 @@ +import asyncMiddleware from "./asyncMiddleware"; // Importing asyncMiddleware for handling asynchronous middleware functions +import cacheMiddleware from "./cacheMiddleware"; // Importing cacheMiddleware for caching mechanism +import requestMiddleware from "./requestMiddleware"; // Importing requestMiddleware for handling request-related middleware + +export { + asyncMiddleware, // Exporting asyncMiddleware for use in Express middleware chain + cacheMiddleware, // Exporting cacheMiddleware for use in Express middleware chain + requestMiddleware // Exporting requestMiddleware for use in Express middleware chain +} diff --git a/health-services/project-factory/src/server/utils/middlewares/requestMiddleware.ts b/health-services/project-factory/src/server/utils/middlewares/requestMiddleware.ts new file mode 100644 index 00000000000..a8bfd34a330 --- /dev/null +++ b/health-services/project-factory/src/server/utils/middlewares/requestMiddleware.ts @@ -0,0 +1,46 @@ +import { NextFunction, Request, Response } from "express"; // Importing necessary modules from Express +const { object, string } = require("yup"); // Importing object and string from yup for schema validation +import { errorResponder } from "../genericUtils"; // Importing errorResponder function from genericUtils +import { logger } from "../logger"; + +// Defining the request schema using yup +const requestSchema = object({ + apiId: string().nullable(), // Nullable string field for API ID + action: string().nullable(), // Nullable string field for action + msgId: string().required(), // Required string field for message ID + authToken: string().nullable(), // Nullable string field for authentication token + userInfo: object().nonNullable() // Non-nullable object field for user information +}); + +// Middleware function to validate request payload +const requestMiddleware = (req: Request, res: Response, next: NextFunction) => { + try { + logger.info(`RECEIVED A HTTP REQUEST :: URI :: ${req.url}`); + // Check if the content type is 'application/json' + const contentType = req.headers['content-type']; + if (!contentType || !contentType.split(';').map(part => part.trim()).includes('application/json')) { + // If content type is not 'application/json', throw Unsupported Media Type error + let e: any = new Error("Unsupported Media Type: Content-Type should be 'application/json'"); + e = Object.assign(e, { status: 415, code: "UNSUPPORTED_MEDIA_TYPE" }); + errorResponder(e, req, res, 415) + return; + } + // Check if tenantId is missing in RequestInfo.userInfo + if (!req?.body?.RequestInfo?.userInfo?.tenantId) { + // If tenantId is missing, throw Validation Error + let e: any = new Error("RequestInfo.userInfo.tenantId is missing"); + e = Object.assign(e, { status: 400, code: "VALIDATION_ERROR" }); + errorResponder(e, req, res, 400) + return; + } + // Validate request payload against the defined schema + requestSchema.validateSync(req.body.RequestInfo); + // If validation succeeds, proceed to the next middleware + next(); + } catch (error) { + // If an error occurs during validation process, handle the error using errorResponder function + errorResponder(error, req, res); + } +}; + +export default requestMiddleware; // Exporting the requestMiddleware function for use in Express middleware chain diff --git a/health-services/project-factory/src/server/utils/processTrackUtils.ts b/health-services/project-factory/src/server/utils/processTrackUtils.ts new file mode 100644 index 00000000000..6d80346825f --- /dev/null +++ b/health-services/project-factory/src/server/utils/processTrackUtils.ts @@ -0,0 +1,224 @@ +import config from './../config'; +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; + `; + } + + const queryResponse = await executeQuery(query, values); + + 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: 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 { + const processDetailsArray = await getProcessDetails(campaignId, type); + + if (processDetailsArray.length === 0) { + logger.info('No process details found, nothing to persist'); + return; + } + + 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); +} + +// 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, + createdTime: currentTime, + lastModifiedTime: currentTime, + details: details || {}, + additionalDetails: additionalDetails || {}, + }; + + 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)); +} + +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, getProcessDetails, createProcessTracks }; diff --git a/health-services/project-factory/src/server/utils/redisUtils.ts b/health-services/project-factory/src/server/utils/redisUtils.ts new file mode 100644 index 00000000000..f62177928d9 --- /dev/null +++ b/health-services/project-factory/src/server/utils/redisUtils.ts @@ -0,0 +1,29 @@ +import Redis from "ioredis"; +import config from "../config"; + +const redis = new Redis({ + host: config.host.redisHost, + port: parseInt(config.cacheValues.redisPort), + retryStrategy(times) { + if (times > 1) { + return null; // Stop retrying after one attempt + } + return 500; // Delay before retrying (in milliseconds) + }, + maxRetriesPerRequest: 1, // Allow only 1 retry per request + reconnectOnError(err) { + return false; // Do not reconnect on errors + }, +}); + +async function checkRedisConnection(): Promise { + try { + await redis.ping(); + return true; + } catch (error) { + console.error("Redis connection error:", error); + return false; + } +} + +export { redis, checkRedisConnection }; diff --git a/health-services/project-factory/src/server/utils/request.ts b/health-services/project-factory/src/server/utils/request.ts new file mode 100644 index 00000000000..ef23426cc0e --- /dev/null +++ b/health-services/project-factory/src/server/utils/request.ts @@ -0,0 +1,193 @@ +import { Response } from "express"; // Importing necessary module Response from Express +import { getFormattedStringForDebug, logger } from "./logger"; // Importing logger from logger module +import { throwErrorViaRequest } from "./genericUtils"; // Importing necessary functions from genericUtils module +import config from "../config"; +import { redis, checkRedisConnection } from "./redisUtils"; // Importing checkRedisConnection function + +var Axios = require("axios").default; // Importing axios library +var get = require("lodash/get"); // Importing get function from lodash library +const axiosInstance = Axios.create({ + timeout: 0, // Set timeout to 0 to wait indefinitely + maxContentLength: Infinity, + maxBodyLength: Infinity, +}); + +// Axios interceptor to handle response errors +axiosInstance.interceptors.response.use( + (res: Response) => { + return res; + }, + (err: any) => { + // If there is no response object in the error, create one with status 400 + if (err && !err.response) { + err.response = { + status: 400, + }; + } + // If there is a response but no data, create an error object with the error message + if (err && err.response && !err.response.data) { + err.response.data = { + Errors: [{ code: err.message }], + }; + } + throw err; // Throw the error + } +); + +// Default header for HTTP requests +export const defaultheader = { + "content-type": "application/json;charset=UTF-8", + accept: "application/json, text/plain, */*", +}; + +// Function to extract service name from URL +const getServiceName = (url = "") => url && url.slice && url.slice(url.lastIndexOf(url.split("/")[3])); + +const cacheEnabled = config.cacheValues.cacheEnabled; // Variable to indicate whether caching is enabled or not + +/** + * Used to Make API call through axios library + * + * @param {string} _url - The URL to make the HTTP request to + * @param {Object} _requestBody - The request body + * @param {Object} _params - The request parameters + * @param {string} _method - The HTTP method (default to post) + * @param {string} responseType - The response type + * @param {Object} headers - The request headers + * @param {any} sendStatusCode - Flag to determine whether to send status code along with response data + * @returns {Promise} - Returns the response data or throws an error + */ +const httpRequest = async ( + _url: string, + _requestBody: any, + _params: any = {}, + _method: string = "post", + responseType: string = "", + headers: any = defaultheader, + sendStatusCode: any = false, + retry: any = false, + dontThrowError: any = false +): Promise => { + let attempt = 0; + const maxAttempts = parseInt(config.values.maxHttpRetries) || 4; + const cacheKey = headers && headers.cachekey ? `cache:${headers.cachekey}` : null; // Create cache key + const cacheTTL = 300; // TTL in seconds (5 minutes) + + while (attempt < maxAttempts) { + try { + const isRedisConnected = await checkRedisConnection(); + if (cacheKey && cacheEnabled && isRedisConnected) { + const 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 + } + logger.info("NO CACHE FOUND :: REQUEST :: " + cacheKey); + } + + logger.info( + "INTER-SERVICE :: REQUEST :: " + + getServiceName(_url) + + " CRITERIA :: " + + JSON.stringify(_params) + ); + logger.debug("INTER-SERVICE :: REQUESTBODY :: " + getFormattedStringForDebug(_requestBody)); + + const response = await axiosInstance({ + method: _method, + url: _url, + data: _requestBody, + params: _params, + headers: { ...defaultheader, ...headers }, + responseType, + }); + + const responseStatus = parseInt(get(response, "status"), 10); + logger.info( + "INTER-SERVICE :: SUCCESS :: " + + getServiceName(_url) + + ":: CODE :: " + + responseStatus + ); + logger.debug("INTER-SERVICE :: RESPONSEBODY :: " + getFormattedStringForDebug(response.data)); + + if ([200, 201, 202].includes(responseStatus)) { + if (cacheKey && isRedisConnected) { + await redis.set(cacheKey, JSON.stringify(response.data), "EX", cacheTTL); // Cache the response data with TTL + } + return sendStatusCode ? { ...response.data, statusCode: responseStatus } : response.data; + } + } catch (error: any) { + const errorResponse = error?.response; + logger.error( + "INTER-SERVICE :: FAILURE :: " + + getServiceName(_url) + + ":: CODE :: " + + errorResponse?.status + + ":: ERROR :: " + + (errorResponse?.data?.Errors?.[0]?.code || error) + + ":: DESCRIPTION :: " + + errorResponse?.data?.Errors?.[0]?.description + ); + logger.error( + "error occurred while making request to " + + getServiceName(_url) + + ": error response :" + + (errorResponse ? parseInt(errorResponse?.status, 10) : error?.message) + ); + logger.error(":: ERROR STACK :: " + (error?.stack || error)); + logger.warn( + `Error occurred while making request to ${getServiceName(_url)}: with error response ${JSON.stringify( + errorResponse?.data || { Errors: [{ code: error.message, description: error.stack }] } + )}` + ); + if (retry) { + 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 }] }; + } else { + throwTheHttpError(errorResponse, error, _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 }] } + )}` + ); + return errorResponse?.data || { Errors: [{ code: error.message, description: error.stack }] }; + } else { + throwTheHttpError(errorResponse, error, _url); + } + } + } +}; + +function throwTheHttpError(errorResponse?: any, error?: any, _url?: string) { + // Throw error response via request if error response contains errors + if (errorResponse?.data?.Errors?.[0]) { + errorResponse.data.Errors[0].status = errorResponse?.data?.Errors?.[0]?.status || errorResponse?.status; + throwErrorViaRequest(errorResponse?.data?.Errors?.[0]); + } else { + // Throw error message via request + throwErrorViaRequest( + "error occurred while making request to " + + getServiceName(_url) + + ": error response :" + + (errorResponse ? parseInt(errorResponse?.status, 10) : error?.message) + ); + } +} + +export { httpRequest }; // Exporting the httpRequest function for use in other modules diff --git a/health-services/project-factory/src/server/utils/targetUtils.ts b/health-services/project-factory/src/server/utils/targetUtils.ts new file mode 100644 index 00000000000..74a91782dba --- /dev/null +++ b/health-services/project-factory/src/server/utils/targetUtils.ts @@ -0,0 +1,137 @@ +import config from '../config' +import { checkIfSourceIsMicroplan, getConfigurableColumnHeadersBasedOnCampaignType, getLocalizedName } from './campaignUtils'; +import _ from 'lodash'; +import { replicateRequest } from './genericUtils'; +import { callGenerate } from './generateUtils'; + + +async function generateDynamicTargetHeaders(request: any, campaignObject: any, localizationMap?: any) { + const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); + let headerColumnsAfterHierarchy: any; + if (isDynamicTargetTemplateForProjectType(campaignObject?.projectType) && campaignObject.deliveryRules && campaignObject.deliveryRules.length > 0 && !isSourceMicroplan) { + const modifiedUniqueDeliveryConditions = modifyDeliveryConditions(campaignObject.deliveryRules); + headerColumnsAfterHierarchy = generateTargetColumnsBasedOnDeliveryConditions(modifiedUniqueDeliveryConditions, localizationMap); + + } + else { + headerColumnsAfterHierarchy = await getConfigurableColumnHeadersBasedOnCampaignType(request); + headerColumnsAfterHierarchy.shift(); + } + return headerColumnsAfterHierarchy; +} + + +function modifyDeliveryConditions(dataa: any[]): any { + let resultSet = new Set(); + dataa.forEach((delivery) => { + const conditions = delivery.conditions; + let newArray: any[] = []; + + conditions.forEach((item: any) => { + const existingIndex = newArray.findIndex( + (element) => element.attribute.code === item.attribute + ); + + if (existingIndex !== -1) { + const existingItem = newArray[existingIndex]; + // Combine conditions if necessary + if (existingItem.operator.code !== item.operator.code) { + newArray[existingIndex] = { + attribute: existingItem.attribute, + operator: { code: "IN_BETWEEN" }, + toValue: + existingItem.value && item.value ? Math.max(existingItem.value, item.value) : null, + fromValue: + existingItem.value && item.value ? Math.min(existingItem.value, item.value) : null + }; + } + } else { + // If attribute does not exist in newArray, add the item + newArray.push({ + attribute: { code: item.attribute }, + operator: { code: item.operator }, + value: item.value + }); + } + }); + newArray.map((element: any) => { + const stringifiedElement = JSON.stringify(element); // Convert object to string + resultSet.add(stringifiedElement); + }) + }); + return resultSet; +} + + +function generateTargetColumnsBasedOnDeliveryConditions(uniqueDeliveryConditions: any, localizationMap?: any) { + const targetColumnsBasedOnDeliveryConditions: string[] = []; + uniqueDeliveryConditions.forEach((str: any, index: number) => { + const uniqueDeliveryConditionsObject = JSON.parse(str); // Parse JSON string into object + const targetColumnString = createTargetString(uniqueDeliveryConditionsObject, localizationMap); + targetColumnsBasedOnDeliveryConditions.push(targetColumnString); + }); + if (targetColumnsBasedOnDeliveryConditions.length > 18) { + targetColumnsBasedOnDeliveryConditions.splice(18); + targetColumnsBasedOnDeliveryConditions.push(getLocalizedName("OTHER_TARGETS", localizationMap)); + } + return targetColumnsBasedOnDeliveryConditions; +} + +function createTargetString(uniqueDeliveryConditionsObject: any, localizationMap?: any) { + let targetString: any; + const prefix = getLocalizedName("HCM_ADMIN_CONSOLE_TARGET_SMC", localizationMap); + const attributeCode = getLocalizedName(uniqueDeliveryConditionsObject.attribute.code.toUpperCase(), localizationMap); + const operatorMessage = getLocalizedName(uniqueDeliveryConditionsObject.operator.code, localizationMap); + const localizedFROM = getLocalizedName("FROM", localizationMap); + const localizedTO = getLocalizedName("TO", localizationMap); + if (uniqueDeliveryConditionsObject.operator.code === 'IN_BETWEEN') { + targetString = `${prefix} ${attributeCode} ${localizedFROM} ${uniqueDeliveryConditionsObject.fromValue} ${localizedTO} ${uniqueDeliveryConditionsObject.toValue}`; + } else { + targetString = `${prefix} ${attributeCode} ${operatorMessage} ${uniqueDeliveryConditionsObject.value}`; + } + return targetString; +} + +async function updateTargetColumnsIfDeliveryConditionsDifferForSMC(request: any) { + const existingCampaignDetails = request?.body?.ExistingCampaignDetails; + if (existingCampaignDetails) { + if (isDynamicTargetTemplateForProjectType(request?.body?.CampaignDetails?.projectType) && config?.isCallGenerateWhenDeliveryConditionsDiffer && !_.isEqual(existingCampaignDetails?.deliveryRules, request?.body?.CampaignDetails?.deliveryRules)) { + const newRequestBody = { + RequestInfo: request?.body?.RequestInfo, + Filters: { + boundaries: request?.body?.CampaignDetails?.boundaries + } + }; + + const { query } = request; + const params = { + tenantId: request?.body?.CampaignDetails?.tenantId, + forceUpdate: 'true', + hierarchyType: request?.body?.CampaignDetails?.hierarchyType, + campaignId: request?.body?.CampaignDetails?.id + }; + + const newParamsBoundary = { ...query, ...params, type: "boundary" }; + const newRequestBoundary = replicateRequest(request, newRequestBody, newParamsBoundary); + await callGenerate(newRequestBoundary, "boundary", true); + } + } +} + +function isDynamicTargetTemplateForProjectType(projectType: string) { + const projectTypesFromConfig = config?.enableDynamicTemplateFor; + const projectTypesArray = projectTypesFromConfig ? projectTypesFromConfig.split(',') : []; + return projectTypesArray.includes(projectType); +} + + + + + +export { + modifyDeliveryConditions, + generateTargetColumnsBasedOnDeliveryConditions, + generateDynamicTargetHeaders, + updateTargetColumnsIfDeliveryConditionsDifferForSMC, + isDynamicTargetTemplateForProjectType +}; diff --git a/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts b/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts new file mode 100644 index 00000000000..a2528ce515d --- /dev/null +++ b/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts @@ -0,0 +1,46 @@ +import { + getLocaleFromRequest, + getLocalisationModuleName, +} from "../localisationUtils"; +import Localisation from "../../controllers/localisationController/localisation.controller"; +import { logger } from "../logger"; + +/** + * Transforms boundary map into localisation messages and creates localisation entries. + * @param boundaryMap - Map of boundary keys and codes. + * @param hierarchyType - Type of hierarchy for the localisation module. + * @param request - Request object containing necessary information. + */ +export const transformAndCreateLocalisation = ( + boundaryMap: any, + request: any +) => { + const { tenantId, hierarchyType } = request?.body?.ResourceDetails || {}; + + // Get localisation module name based on hierarchy type + const module = getLocalisationModuleName(hierarchyType); + + // Get locale from request object + const locale = getLocaleFromRequest(request); + + // Array to store localisation messages + const localisationMessages: any = []; + + // Iterate over boundary map to transform into localisation messagess + boundaryMap.forEach((code: string, boundary: any) => { // Add transformed message to localisation messages array + localisationMessages.push({ + code, + message: boundary.value, + module, + locale, + }); + + }) + + logger.info("localisation message transformed successfully from the boundary map") + // Instantiate localisation controller + const localisation = Localisation.getInstance(); + + // Call method to create localisation entries + localisation.createLocalisation(localisationMessages, tenantId,request); + }; diff --git a/health-services/project-factory/src/server/utils/transforms/projectTypeUtils.ts b/health-services/project-factory/src/server/utils/transforms/projectTypeUtils.ts new file mode 100644 index 00000000000..e279306f7ce --- /dev/null +++ b/health-services/project-factory/src/server/utils/transforms/projectTypeUtils.ts @@ -0,0 +1,328 @@ +import { getFormattedStringForDebug, logger } from "../logger"; + +const MAX_AGE = 100; +const MAX_AGE_IN_MONTHS = MAX_AGE * 12; +/* +TODO: Update configObject with appropriate values. +This object contains configuration settings for delivery strategies and wait times. +*/ + + +/* TODO: Update the logic to fetch the projecttype master */ +const defaultProjectType: any = { + /* + Define default project types with their respective properties. + Each project type represents a specific type of campaign. + */ + "MR-DN": { + id: "b1107f0c-7a91-4c76-afc2-a279d8a7b76a", + name: "configuration for Multi Round Campaigns", + code: "MR-DN", + group: "MALARIA", + beneficiaryType: "INDIVIDUAL", + resources: [], + observationStrategy: "DOT1", + validMinAge: 3, + validMaxAge: 60, + cycles: [], + }, + "LLIN-mz": { + id: "192a20d1-0edd-4108-925a-f37bf544d6c4", + name: "Project type configuration for IRS - Nampula Campaigns", + code: "LLIN-mz", + group: "IRS - Nampula", + beneficiaryType: "HOUSEHOLD", + eligibilityCriteria: ["All households are eligible."], + dashboardUrls: { + NATIONAL_SUPERVISOR: + "/digit-ui/employee/dss/landing/national-health-dashboard", + PROVINCIAL_SUPERVISOR: + "/digit-ui/employee/dss/dashboard/provincial-health-dashboard", + DISTRICT_SUPERVISOR: + "/digit-ui/employee/dss/dashboard/district-health-dashboard", + }, + taskProcedure: [ + "1 DDT is to be distributed per house.", + "1 Malathion is to be distributed per house.", + "1 Pyrethroid is to be distributed per house.", + ], + resources: [], + }, +}; + +/* +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; +}; +/* +Enrich project details from campaign details. +*/ +export const enrichProjectDetailsFromCampaignDetails = ( + CampaignDetails: any = {}, + projectTypeObject: any = {} +) => { + var { tenantId, projectType, startDate, endDate, campaignName } = + CampaignDetails; + logger.info("campaign transformation for project type : " + projectType); + logger.debug( + "project type : " + getFormattedStringForDebug(projectTypeObject) + ); + const defaultProject = + projectTypeObject || + defaultProjectType?.[projectType] || + defaultProjectType?.["MR-DN"]; + return [ + { + tenantId, + projectType, + startDate, + endDate, + projectSubType: projectType, + department: defaultProject?.group, + description: defaultProject?.name, + projectTypeId: defaultProject?.id, + name: campaignName, + additionalDetails: { + projectType: projectTypeConversion(defaultProject, CampaignDetails), + }, + }, + ]; +}; + + +/* construct max and min age */ +const getMinAndMaxAge = (deliveries = []) => { + // Flatten the conditions arrays from all delivery objects and filter to keep only 'Age' attributes + const ageConditions = deliveries + .flatMap((e: any) => e?.conditions) + .filter((obj) => obj?.attribute == "Age"); + + // If no age conditions are found, return the default range + if (ageConditions.length === 0) { + return { min: 0, max: MAX_AGE_IN_MONTHS }; + } + + // Initialize min and max values + let min = Infinity; + let max = -Infinity; + + // Iterate through the ageConditions to find the actual min and max values + for (const condition of ageConditions) { + const value = condition?.value; + if (value !== undefined) { + if (value < min) min = value; + if (value > max) max = value; + } + } + + // Return the min and max values, with default fallbacks if no valid ages were found + return { + min: min !== Infinity ? min : 0, + max: max !== -Infinity ? max : MAX_AGE_IN_MONTHS, + }; +}; + + + +type MandatoryWaitDays = { + default: string | null; + other: string | null; +}; + +interface ConfigObject { + mandatoryWaitSinceLastCycleInDays: MandatoryWaitDays; + mandatoryWaitSinceLastDeliveryInDays: MandatoryWaitDays; +} + +// Configuration for default values +const configObject: ConfigObject = { + mandatoryWaitSinceLastCycleInDays: { + default: null, + other: "30" + }, + mandatoryWaitSinceLastDeliveryInDays: { + default: null, + other: null + } +}; + +// Define types for product variants and conditions +type ProductVariant = { + value: string; + name: string; + count: number; +}; + +type ConditionOperator = 'LESS_THAN' | 'LESS_THAN_EQUAL_TO' | 'GREATER_THAN' | 'GREATER_THAN_EQUAL_TO' | 'EQUAL_TO'; + +type Condition = { + attribute: string; + operator: ConditionOperator; + value: number | string; +}; + +type DeliveryItem = { + cycleNumber: number; + deliveryNumber: number; + deliveryType: string; + deliveryRuleNumber: number; + products: ProductVariant[]; + conditions: Condition[]; + startDate:any, + endDate:any +}; + +type FormattedCondition = Record>; + +type DoseCriterion = { + ProductVariants: { + isBaseUnitVariant: boolean; + productVariantId: string; + quantity: number; + }[]; + condition: string; +}; + +type Delivery = { + id: string; + deliveryStrategy: string; + mandatoryWaitSinceLastDeliveryInDays: string | null; + doseCriteria: DoseCriterion[]; +}; + +type TransformedCycle = { + id: string; + mandatoryWaitSinceLastCycleInDays: string | null; + deliveries: Delivery[]; + startDate:any, + endDate:any, +}; + +// Helper functions + +// Get unique product variants +const getUniqueArrayByProductVariantId = ( + array: { isBaseUnitVariant: boolean; productVariantId: string; quantity: number; }[] +): { isBaseUnitVariant: boolean; productVariantId: string; quantity: number; }[] => { + return array.filter( + (value, index, self) => + index === self.findIndex(t => t.productVariantId === value.productVariantId) + ); +}; + +// Construct conditions in a simplified form +const getConditionString = (condition: Record, attribute: string): string => { + let conditionStr = ''; + if (condition.LESS_THAN !== undefined) { + conditionStr += `${attribute}<${condition.LESS_THAN}`; + } + if (condition.LESS_THAN_EQUAL_TO !== undefined) { + conditionStr += `${attribute}<=${condition.LESS_THAN_EQUAL_TO}`; + } + if (condition.GREATER_THAN !== undefined) { + conditionStr = `${condition.GREATER_THAN}<${attribute}and` + conditionStr; + } + if (condition.GREATER_THAN_EQUAL_TO !== undefined) { + conditionStr = `${condition.GREATER_THAN_EQUAL_TO}<=${attribute}and` + conditionStr; + } + if (condition.EQUAL_TO !== undefined) { + if (attribute === "gender") { + conditionStr += `${attribute}==${condition.EQUAL_TO === "MALE" ? 0 : 1}`; + } else { + conditionStr += `${attribute}=${condition.EQUAL_TO}`; + } + } + return conditionStr; +}; + +// Function to generate the condition string from an array of conditions +const getRequiredCondition = (conditions: Condition[]): string => { + const formattedConditions: FormattedCondition = conditions.reduce((acc:any, { attribute, operator, value }) => { + attribute = attribute.toLowerCase(); + if (!acc[attribute]) { + acc[attribute] = {}; + } + acc[attribute][operator] = value; + return acc; + }, {} as FormattedCondition); + + const conditionStrings = Object.keys(formattedConditions).map(attribute => + getConditionString(formattedConditions[attribute], attribute) + ); + + return conditionStrings.join('and'); +}; + +// Transformation function +const transformData = (input: DeliveryItem[]): TransformedCycle[] => { + const groupedByCycle = input.reduce>((acc, item) => { + const { cycleNumber, deliveryNumber, deliveryType, products, conditions,startDate,endDate } = item; + + if (!acc[cycleNumber]) { + acc[cycleNumber] = { + id: cycleNumber.toString(), + mandatoryWaitSinceLastCycleInDays: configObject.mandatoryWaitSinceLastCycleInDays.default, + deliveries: [], + startDate, + endDate + }; + } + + const delivery: Delivery = { + id: deliveryNumber.toString(), + deliveryStrategy: deliveryType, + mandatoryWaitSinceLastDeliveryInDays: configObject.mandatoryWaitSinceLastDeliveryInDays.default, + doseCriteria: [] + }; + + const doseCriteria: DoseCriterion = { + ProductVariants: getUniqueArrayByProductVariantId( + products.map((product, index) => ({ + isBaseUnitVariant: index === 0, + productVariantId: product.value, + quantity: product.count + })) + ), + condition: getRequiredCondition(conditions) + }; + + const existingDelivery = acc[cycleNumber].deliveries.find(d => d.id === deliveryNumber.toString()); + if (existingDelivery) { + existingDelivery.doseCriteria.push(doseCriteria); + } else { + delivery.doseCriteria.push(doseCriteria); + acc[cycleNumber].deliveries.push(delivery); + } + + return acc; + }, {}); + + return Object.values(groupedByCycle); +}; diff --git a/health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts b/health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts new file mode 100644 index 00000000000..783fb22edd8 --- /dev/null +++ b/health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts @@ -0,0 +1,93 @@ +/** + * Transforms generic resource data fetched from the database into a standardized format. + * + * @param {any[]} dbRows - The array of database rows to transform. + * @returns {Object[]} - An array of transformed resource objects. + */ +export const genericResourceTransformer = (dbRows: any[] = []) => { + return dbRows?.map((row: any) => ({ + id: row?.id, + tenantId: row?.tenantid, + status: row?.status, + action: row?.action, + fileStoreId: row?.filestoreid, + processedFilestoreId: row?.processedfilestoreid, + campaignId: row?.campaignid, + type: row?.type, + auditDetails: { + createdBy: row?.createdby, + lastModifiedBy: row?.lastmodifiedby, + createdTime: Number(row?.createdtime), + lastModifiedTime: row?.lastmodifiedtime + ? Number(row?.lastmodifiedtime) + : null, + }, + additionalDetails: row?.additionaldetails, + })); +}; + +/** + * Transforms campaign details fetched from the database into a standardized format. + * + * @param {any[]} dbRows - The array of database rows to transform. + * @returns {Object[]} - An array of transformed campaign detail objects. + */ +export const campaignDetailsTransformer = (dbRows: any[] = []) => { + return dbRows.map((row: any) => ({ + id: row?.id, + tenantId: row?.tenantid, + status: row?.status, + action: row?.action, + campaignNumber: row?.campaignnumber, + campaignName: row?.campaignname, + projectType: row?.projecttype, + hierarchyType: row?.hierarchytype, + boundaryCode: row?.boundarycode, + projectId: row?.projectid, + startDate: Number(row?.startdate), + endDate: Number(row?.enddate), + createdBy: row?.createdby, + lastModifiedBy: row?.lastmodifiedby, + createdTime: Number(row?.createdtime), + lastModifiedTime: row?.lastmodifiedtime + ? Number(row?.lastmodifiedtime) + : null, + campaignDetails: row?.campaigndetails, + additionalDetails: row?.additionaldetails, + })); +}; + +/** + * Transforms generated resource data fetched from the database into a standardized format. + * + * @param {any[]} dbRows - The array of database rows to transform. + * @returns {Object[]} - An array of transformed resource objects. + */ +export const generatedResourceTransformer = (dbRows: any[] = []) => { + return dbRows.map((item: any) => { + // Extract and structure audit details + item.auditDetails = { + lastModifiedTime: item.lastmodifiedtime, + createdTime: item.createdtime, + lastModifiedBy: item.lastmodifiedby, + createdBy: item.createdby, + }; + + // Rename and restructure properties + item.tenantId = item.tenantid; + item.additionalDetails = item.additionaldetails; + item.additionalDetails.Filters = item?.additionaldetails?.filters ? {} : item?.additionaldetails?.filters; + item.fileStoreid = item.filestoreid; + + // Remove unnecessary properties + delete item.additionaldetails; + delete item.lastmodifiedtime; + delete item.createdtime; + delete item.lastmodifiedby; + delete item.createdby; + delete item.filestoreid; + delete item.tenantid; + + return { ...item }; // Return the transformed object + }); +}; diff --git a/health-services/project-factory/src/server/validators/campaignValidators.ts b/health-services/project-factory/src/server/validators/campaignValidators.ts new file mode 100644 index 00000000000..1af1e291eba --- /dev/null +++ b/health-services/project-factory/src/server/validators/campaignValidators.ts @@ -0,0 +1,1243 @@ +import createAndSearch from "../config/createAndSearch"; +import config from "../config"; +import { getFormattedStringForDebug, logger } from "../utils/logger"; +import { defaultheader, httpRequest } from "../utils/request"; +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 { validateBodyViaSchema, validateCampaignBodyViaSchema, validateHierarchyType } from "./genericValidator"; +import { searchCriteriaSchema } from "../config/models/SearchCriteria"; +import { searchCampaignDetailsSchema } from "../config/models/searchCampaignDetails"; +import { campaignDetailsDraftSchema } from "../config/models/campaignDetailsDraftSchema"; +import { downloadRequestSchema } from "../config/models/downloadRequestSchema"; +import { createRequestSchema } from "../config/models/createRequestSchema" +import { getSheetData, getTargetWorkbook } from "../api/genericApis"; +const _ = require('lodash'); +import { searchDataService } from "../service/dataManageService"; +import { searchProjectTypeCampaignService } from "../service/campaignManageService"; +import { campaignStatuses, resourceDataStatuses } from "../config/constants"; +import { getBoundaryColumnName, getBoundaryTabName } from "../utils/boundaryUtils"; +import addAjvErrors from "ajv-errors"; +import { generateTargetColumnsBasedOnDeliveryConditions, isDynamicTargetTemplateForProjectType, modifyDeliveryConditions } from "../utils/targetUtils"; + + + + +function processBoundary(responseBoundaries: any[], request: any, boundaryItems: any[], parentId?: string) { + const { tenantId, hierarchyType } = request.body.ResourceDetails; + boundaryItems.forEach((boundaryItem: any) => { + const { id, code, boundaryType, children } = boundaryItem; + responseBoundaries.push({ tenantId, hierarchyType, parentId, id, code, boundaryType }); + if (children.length > 0) { + processBoundary(responseBoundaries, request, children, id); + } + }); +} +async function fetchBoundariesInChunks(request: any) { + const { tenantId, hierarchyType } = request.body.ResourceDetails; + const params: any = { + tenantId, hierarchyType, includeChildren: true + }; + const responseBoundaries: any[] = []; + const header = { + ...defaultheader, + cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, + } + var response = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, request.body, params, undefined, undefined, header); + const TenantBoundary = response.TenantBoundary; + TenantBoundary.forEach((tenantBoundary: any) => { + const { boundary } = tenantBoundary; + processBoundary(responseBoundaries, request, boundary); + }); + return responseBoundaries; +} + +function processBoundaryfromCampaignDetails(responseBoundaries: any[], request: any, boundaryItems: any[]) { + boundaryItems.forEach((boundaryItem: any) => { + const { code, boundaryType, children } = boundaryItem; + responseBoundaries.push({ code, boundaryType }); + if (children.length > 0) { + processBoundaryfromCampaignDetails(responseBoundaries, request, children); + } + }); +} + +async function fetchBoundariesFromCampaignDetails(request: any) { + const { tenantId, hierarchyType } = request.body.CampaignDetails; + const params: any = { + tenantId, hierarchyType, includeChildren: true + }; + const header = { + ...defaultheader, + cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, + } + const responseBoundaries: any[] = []; + var response = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, request.body, params, undefined, undefined, header); + const TenantBoundary = response.TenantBoundary; + TenantBoundary.forEach((tenantBoundary: any) => { + const { boundary } = tenantBoundary; + processBoundaryfromCampaignDetails(responseBoundaries, request, boundary); + }); + return responseBoundaries; +} + +// // Compares unique boundaries with response boundaries and throws error for missing codes. +// function compareBoundariesWithUnique(uniqueBoundaries: any[], responseBoundaries: any[], request: any) { +// // Extracts boundary codes from response boundaries +// const responseBoundaryCodes = responseBoundaries.map(boundary => boundary.code.trim()); + +// // Finds missing codes from unique boundaries +// const missingCodes = uniqueBoundaries.filter(code => !responseBoundaryCodes.includes(code)); + +// // Throws error if missing codes exist +// if (missingCodes.length > 0) { +// throwError( +// "COMMON", +// 400, +// "VALIDATION_ERROR", +// `Boundary codes ${missingCodes.join(', ')} do not exist in hierarchyType ${request?.body?.ResourceDetails?.hierarchyType}` +// ); +// } +// } + +// Validates unique boundaries against the response boundaries. +// async function validateUniqueBoundaries(uniqueBoundaries: any[], request: any) { +// // Fetches response boundaries in chunks +// const responseBoundaries = await fetchBoundariesInChunks(request); + +// // Compares unique boundaries with response boundaries +// compareBoundariesWithUnique(uniqueBoundaries, responseBoundaries, request); +// } + + + + +// async function validateBoundaryData(data: any[], request: any, boundaryColumn: any, 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) { + let columnsToValidate: any; + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + if (isDynamicTargetTemplateForProjectType(campaignObject?.projectType) && campaignObject.deliveryRules && campaignObject.deliveryRules.length > 0) { + + const modifiedUniqueDeliveryConditions = modifyDeliveryConditions(campaignObject.deliveryRules); + columnsToValidate = generateTargetColumnsBasedOnDeliveryConditions(modifiedUniqueDeliveryConditions, localizationMap); + + } + else { + const mdmsResponse = await getMdmsDataBasedOnCampaignType(request); + const columnsNotToBeFreezed = mdmsResponse?.columnsNotToBeFreezed; + const requiredColumns = mdmsResponse?.required; + columnsToValidate = columnsNotToBeFreezed.filter((element: any) => requiredColumns.includes(element)); + } + const localizedTargetColumnNames = getLocalizedHeaders(columnsToValidate, localizationMap); + for (const key in data) { + if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { + if (Array.isArray(data[key])) { + const boundaryData = data[key]; + boundaryData.forEach((obj: any, index: number) => { + for (const targetColumn of localizedTargetColumnNames) { + const target = obj[targetColumn]; + if (!target) { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Target value is missing at row ${obj['!row#number!']} in sheet ${key}.(Targets values can only be positive numbers less than 1 Million)`, + sheetName: key + }); + } else if (typeof target !== 'number') { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Target value at row ${obj['!row#number!']} in sheet ${key} is not a number.(Targets values can only be positive numbers less than 1 Million)`, + sheetName: key + }); + } else if (target <= 0 || target > 1000000) { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Target value at row ${obj['!row#number!']} in sheet ${key} is out of range.(Targets values can only be positive numbers less than 1 Million)`, + sheetName: key + }); + } else if (!Number.isInteger(target)) { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Target value at row ${obj['!row#number!']} in sheet ${key} is not an integer.(Targets values can only be positive numbers less than 1 Million)`, + sheetName: key + }); + } + } + }); + } + } + } +} + +async function validateUnique(schema: any, data: any[], request: any) { + const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId); + if (schema?.unique) { + const uniqueElements = schema.unique; + const errors = []; + + for (const element of uniqueElements) { + const uniqueMap = new Map(); + + // Iterate over each data object and check uniqueness + for (const item of data) { + const uniqueIdentifierColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName; + const localizedUniqueIdentifierColumnName = await getLocalizedName(uniqueIdentifierColumnName, localizationMap); + const value = item[element]; + const rowNum = item['!row#number!']; + if (!localizedUniqueIdentifierColumnName || !item[localizedUniqueIdentifierColumnName]) { + // Check if the value is already in the map + if (uniqueMap.has(value)) { + errors.push(`Duplicate value '${value}' found for '${element}' at row number ${rowNum}.`); + } + // Add the value to the map + uniqueMap.set(value, rowNum); + } + } + } + + if (errors.length > 0) { + // Throw an error or return the errors based on your requirement + throwError("FILE", 400, "INVALID_FILE_ERROR", errors.join(" ; ")); + } + } +} + +function validatePhoneNumber(datas: any[], localizationMap: any) { + var digitErrorRows = []; + var missingNumberRows = []; + for (const data of datas) { + const phoneColumn = getLocalizedName("HCM_ADMIN_CONSOLE_USER_PHONE_NUMBER", localizationMap); + if (data[phoneColumn]) { + var phoneNumber = data[phoneColumn]; + phoneNumber = phoneNumber.toString().replace(/^0+/, ''); + if (phoneNumber.length != 10) { + digitErrorRows.push(data["!row#number!"]); + } + } + else { + missingNumberRows.push(data["!row#number!"]); + } + } + var isError = false; + var errorMessage = ""; + if (digitErrorRows.length > 0) { + isError = true; + errorMessage = "PhoneNumber should be of 10 digit on rows " + digitErrorRows.join(" , "); + } + if (missingNumberRows.length > 0) { + isError = true; + if (errorMessage.length > 0) { + errorMessage += " :: "; + } + errorMessage += "PhoneNumber is missing on rows " + missingNumberRows.join(" , "); + } + if (isError) { + throwError("COMMON", 400, "VALIDATION_ERROR", errorMessage); + } +} + +async function changeSchemaErrorMessage(schema: any, localizationMap?: any) { + if (schema?.errorMessage) { + for (const key in schema.errorMessage) { + const value = schema.errorMessage[key]; + delete schema.errorMessage[key]; + schema.errorMessage[getLocalizedName(key, localizationMap)] = value; + } + } + return schema; // Return unmodified schema if no error message +} + + + +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 + 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") { + 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 }); + } + } + }); + 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`; + } + 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."); + } + } else { + throwError("FILE", 400, "INVALID_FILE_ERROR", "Data rows cannot be empty"); + } + } else { + logger.info("Skipping schema validation"); + } +} + + + +async function validateSheetData(data: any, request: any, schema: any, boundaryValidation: any, localizationMap?: { [key: string]: string }) { + await validateViaSchema(data, schema, request, localizationMap); +} + +async function validateTargetSheetData(data: any, request: any, boundaryValidation: any, differentTabsBasedOnLevel: any, localizationMap?: any) { + try { + const errors: any[] = []; + await validateHeadersOfTargetSheet(request, differentTabsBasedOnLevel, localizationMap); + if (boundaryValidation) { + // const localizedBoundaryValidationColumn = getLocalizedName(boundaryValidation?.column, localizationMap) + // await validateTargetBoundaryData(data, request, localizedBoundaryValidationColumn, errors, localizationMap); + await validateTargets(request, data, errors, localizationMap); + } + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; + if (request?.body?.sheetErrorDetails && Array.isArray(request?.body?.sheetErrorDetails) && request?.body?.sheetErrorDetails?.length > 0) { + request.body.ResourceDetails.status = resourceDataStatuses.invalid; + } + await generateProcessedFileAndPersist(request, localizationMap); + logger.info("target sheet data validation completed"); + } + catch (error) { + console.log(error) + await handleResouceDetailsError(request, error); + } +} + + +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, differentTabsBasedOnLevel, localizationMap); + logger.info("finalValidHeadersForTargetSheetAsPerCampaignType :" + JSON.stringify(finalValidHeadersForTargetSheetAsPerCampaignType)); + logger.info("validating headers of target sheet started") + validateHeadersOfTabsWithTargetInTargetSheet(targetWorkbook, finalValidHeadersForTargetSheetAsPerCampaignType); + logger.info("validation of target sheet headers completed") +} + + +function validateBooleanField(obj: any, fieldName: any, index: any) { + if (!obj.hasOwnProperty(fieldName)) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Object at index ${index} is missing field "${fieldName}".`); + } + + if (typeof obj[fieldName] !== 'boolean') { + throwError("COMMON", 400, "VALIDATION_ERROR", `Object at index ${index} has invalid type for field "${fieldName}". It should be a boolean.`); + } +} + +function validateStringField(obj: any, fieldName: any, index: any) { + if (!obj.hasOwnProperty(fieldName)) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Object at index ${index} is missing field "${fieldName}".`); + } + if (typeof obj[fieldName] !== 'string') { + throwError("COMMON", 400, "VALIDATION_ERROR", `Object at index ${index} has invalid type for field "${fieldName}". It should be a string.`); + } + if (obj[fieldName].length < 1) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Object at index ${index} has empty value for field "${fieldName}".`); + } + if (obj[fieldName].length > 128) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Object at index ${index} has value for field "${fieldName}" that exceeds the maximum length of 128 characters.`); + } +} + +function validateStorageCapacity(obj: any, index: any) { + if (!obj.hasOwnProperty('storageCapacity')) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Object at index ${index} is missing field "storageCapacity".`); + } + if (typeof obj.storageCapacity !== 'number') { + throwError("COMMON", 400, "VALIDATION_ERROR", `Object at index ${index} has invalid type for field "storageCapacity". It should be a number.`); + } +} + + +async function validateCampaignId(request: any) { + const { campaignId, tenantId, type } = request?.body?.ResourceDetails; + if (type == "boundary") { + return; + } + if (!campaignId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignId is missing"); + } + else { + const searchBody = { + CampaignDetails: { + ids: [campaignId], + tenantId: tenantId + } + } + const req: any = replicateRequest(request, searchBody); + const response = await searchProjectTypeCampaignService(req); + if (response?.CampaignDetails?.[0]) { + const campaign = response?.CampaignDetails?.[0] + if (!campaign?.boundaries) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Campaign with given campaignId does not have any boundaries"); + } + if (!Array.isArray(campaign?.boundaries)) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Boundaries of campaign with given campaignId is not an array"); + } + if (campaign?.boundaries?.length === 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Campaign with given campaignId does not have any boundaries"); + } + } + else { + throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND", "Campaign not found while validating campaignId"); + } + } +} + + +async function validateCreateRequest(request: any, localizationMap?: any) { + if (!request?.body?.ResourceDetails || Object.keys(request.body.ResourceDetails).length === 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", "ResourceDetails is missing or empty or null"); + } + else { + // validate create request body + validateBodyViaSchema(createRequestSchema, request.body.ResourceDetails); + await validateCampaignId(request); + await validateHierarchyType(request, request?.body?.ResourceDetails?.hierarchyType, request?.body?.ResourceDetails?.tenantId); + if (request?.body?.ResourceDetails?.tenantId != request?.body?.RequestInfo?.userInfo?.tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is not matching with userInfo"); + } + const fileUrl = await validateFile(request); + const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId); + if (request.body.ResourceDetails.type == 'boundary') { + await validateBoundarySheetData(request, fileUrl, localizationMap); + } + // if (request?.body?.ResourceDetails?.type == 'boundaryWithTarget') { + // const targetWorkbook: any = await getTargetWorkbook(fileUrl); + // const 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); + // } + } +} + +function validateHeadersOfTabsWithTargetInTargetSheet(targetWorkbook: any, expectedHeadersForTargetSheet: any) { + 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 + .filter((header: any) => header !== undefined && header !== null && header.toString().trim() !== '') + .map((header: any) => header.toString().trim()); + if (!_.isEqual(expectedHeadersForTargetSheet, headersToValidate)) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Headers not according to the template in Target sheet ${worksheet.name}`); + } + } + }); +} + +async function validateBoundarySheetData(request: any, fileUrl: any, localizationMap?: any) { + const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap); + const headersOfBoundarySheet = await getHeadersOfBoundarySheet(fileUrl, localizedBoundaryTab, false, localizationMap); + const hierarchy = await getHierarchy(request, request?.body?.ResourceDetails?.tenantId, request?.body?.ResourceDetails?.hierarchyType); + const modifiedHierarchy = hierarchy.map(ele => `${request?.body?.ResourceDetails?.hierarchyType}_${ele}`.toUpperCase()) + const localizedHierarchy = getLocalizedHeaders(modifiedHierarchy, localizationMap); + await validateHeaders(localizedHierarchy, headersOfBoundarySheet, request, localizationMap) + const boundaryData = await getSheetData(fileUrl, localizedBoundaryTab, true, undefined, localizationMap); + //validate for whether root boundary level column should not be empty + validateForRootElementExists(boundaryData, localizedHierarchy, localizedBoundaryTab); + // validate for duplicate rows(array of objects) + validateForDupicateRows(boundaryData); +} + +function validateForRootElementExists(boundaryData: any[], hierachy: any[], sheetName: string) { + const root = hierachy[0]; + if (!(boundaryData.filter(e => e[root]).length == boundaryData.length)) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Invalid Boundary Sheet. Root level Boundary not present in every row of Sheet ${sheetName}`) + } +} +function validateForDupicateRows(boundaryData: any[]) { + const uniqueRows = _.uniqWith(boundaryData, (obj1: any, obj2: any) => { + // Exclude '!row#number!' property when comparing objects + const filteredObj1 = _.omit(obj1, ['!row#number!']); + const filteredObj2 = _.omit(obj2, ['!row#number!']); + return _.isEqual(filteredObj1, filteredObj2); + }); + const duplicateBoundaryRows = boundaryData.filter(e => !uniqueRows.includes(e)); + const duplicateRowNumbers = duplicateBoundaryRows.map(obj => obj['!row#number!']); + const rowNumbersSeparatedWithCommas = duplicateRowNumbers.join(', '); + if (duplicateRowNumbers.length > 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary Sheet has duplicate rows at rowNumber ${rowNumbersSeparatedWithCommas}`); + } +} + +async function validateFile(request: any) { + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: request?.body?.ResourceDetails?.tenantId, fileStoreIds: request?.body?.ResourceDetails?.fileStoreId }, "get"); + if (!fileResponse || !fileResponse.fileStoreIds || !fileResponse.fileStoreIds[0] || !fileResponse.fileStoreIds[0].url) { + throwError("FILE", 400, "INVALID_FILE"); + } + else { + return (fileResponse?.fileStoreIds?.[0]?.url); + } +} + +function validateFacilityCreateData(data: any) { + data.forEach((obj: any) => { + const originalIndex = obj.originalIndex; + + // Validate string fields + const stringFields = ['tenantId', 'name', 'usage']; + stringFields.forEach(field => { + validateStringField(obj, field, originalIndex); + }); + + // Validate storageCapacity + validateStorageCapacity(obj, originalIndex); + + // Validate isPermanent + validateBooleanField(obj, 'isPermanent', originalIndex); + }); + +} + +function throwMissingCodesError(missingCodes: any, hierarchyType: any) { + const missingCodesMessage = missingCodes.map((code: any) => + `'${code.code}' for type '${code.type}'` + ).join(', '); + throwError( + "COMMON", + 400, + "VALIDATION_ERROR", + `The following boundary codes (${missingCodesMessage}) do not exist for hierarchy type '${hierarchyType}'.` + ); +} + +async function validateCampaignBoundary(boundaries: any[], hierarchyType: any, tenantId: any, request: any): Promise { + const boundaryCodesToMatch = Array.from(new Set(boundaries.map((boundary: any) => ({ + code: boundary.code.trim(), + type: boundary.type.trim() + })))); + const responseBoundaries = await fetchBoundariesFromCampaignDetails(request); + const responseBoundaryCodes = responseBoundaries.map(boundary => ({ + code: boundary.code.trim(), + type: boundary.boundaryType.trim() + })); + logger.info("received boundary hiearchy response, checking for valid") + + logger.debug("responseBoundaryCodes " + getFormattedStringForDebug(responseBoundaryCodes)) + logger.debug("boundaryCodesToMatch " + getFormattedStringForDebug(boundaryCodesToMatch)) + function isEqual(obj1: any, obj2: any) { + return obj1.code === obj2.code && obj1.type === obj2.type; + } + + // Find missing codes + const missingCodes = boundaryCodesToMatch.filter(codeToMatch => + !responseBoundaryCodes.some(responseCode => isEqual(codeToMatch, responseCode)) + ); + + if (missingCodes.length > 0) { + throwMissingCodesError(missingCodes, hierarchyType) + } +} + +async function validateProjectCampaignBoundaries(boundaries: any[], hierarchyType: any, tenantId: any, request: any): Promise { + if (!request?.body?.CampaignDetails?.projectId) { + if (boundaries) { + if (!Array.isArray(boundaries)) { + throwError("COMMON", 400, "VALIDATION_ERROR", "boundaries should be an array"); + } + let rootBoundaryCount = 0; + for (const boundary of boundaries) { + if (!boundary.code) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary code is required"); + } + if (!boundary.type) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary type is required"); + } + + if (boundary.isRoot) { + rootBoundaryCount++; + } + } + if (rootBoundaryCount !== 1) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Exactly one boundary should have isRoot=true"); + } + await validateCampaignBoundary(boundaries, hierarchyType, tenantId, request); + } + else { + throwError("COMMON", 400, "VALIDATION_ERROR", "Missing boundaries array"); + } + } +} + +async function validateBoundariesForTabs(CampaignDetails: any, resource: any, request: any, localizedTab: any, localizationMap?: any) { + const { boundaries, tenantId } = CampaignDetails; + const boundaryCodes = new Set(boundaries.map((boundary: any) => boundary.code.trim())); + + // Fetch file response + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId, fileStoreIds: resource.fileStoreId }, "get"); + const datas = await getSheetData(fileResponse?.fileStoreIds?.[0]?.url, localizedTab, true, undefined, localizationMap); + + const boundaryColumn = getLocalizedName(createAndSearch?.[resource.type]?.boundaryValidation?.column, localizationMap); + + // Initialize resource boundary codes as a set for uniqueness + const resourceBoundaryCodesArray: any[] = []; + var activeColumnName: any = null; + if (createAndSearch?.[resource.type]?.activeColumn && createAndSearch?.[resource.type]?.activeColumnName) { + activeColumnName = getLocalizedName(createAndSearch?.[resource.type]?.activeColumnName, localizationMap); + } + datas.forEach((data: any) => { + const codes = data?.[boundaryColumn]?.split(',').map((code: string) => code.trim()) || []; + var active = activeColumnName ? data?.[activeColumnName] : "Active"; + if (active == "Active") { + resourceBoundaryCodesArray.push({ boundaryCodes: codes, rowNumber: data?.['!row#number!'] }) + } + }); + + // Convert sets to arrays for comparison + const boundaryCodesArray = Array.from(boundaryCodes); + var errors = [] + // Check for missing boundary codes + for (const rowData of resourceBoundaryCodesArray) { + var missingBoundaries = rowData.boundaryCodes.filter((code: any) => !boundaryCodesArray.includes(code)); + if (missingBoundaries.length > 0) { + const errorString = `The following boundary codes are not present in selected boundaries : ${missingBoundaries.join(', ')}` + errors.push({ status: "BOUNDARYERROR", rowNumber: rowData.rowNumber, errorDetails: errorString }) + } + } + if (errors?.length > 0) { + request.body.ResourceDetails.status = resourceDataStatuses.invalid + } + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; +} + +async function validateBoundaryOfResouces(CampaignDetails: any, request: any, localizationMap?: any) { + const resource = request?.body?.ResourceDetails + if (resource?.type == "user" || resource?.type == "facility") { + const localizedTab = getLocalizedName(createAndSearch?.[resource.type]?.parseArrayConfig?.sheetName, localizationMap); + await validateBoundariesForTabs(CampaignDetails, resource, request, localizedTab, localizationMap) + } +} + + +async function validateResources(resources: any, request: any) { + for (const resource of resources) { + if (resource?.resourceId) { + var searchBody = { + RequestInfo: request?.body?.RequestInfo, + SearchCriteria: { + id: [resource?.resourceId], + tenantId: request?.body?.CampaignDetails?.tenantId + } + } + const req: any = replicateRequest(request, searchBody); + const res: any = await searchDataService(req); + if (res?.[0]) { + if (!(res?.[0]?.status == resourceDataStatuses.completed && res?.[0]?.action == "validate")) { + logger.error(`Error during validation of type ${resource.type}, validation is not successful or not completed. Resource id : ${resource?.resourceId}`); + throwError("COMMON", 400, "VALIDATION_ERROR", `Error during validation of type ${resource.type}, validation is not successful or not completed.`); + } + if (res?.[0]?.fileStoreId != resource?.filestoreId) { + logger.error(`fileStoreId doesn't match for resource with Id ${resource?.resourceId}. Expected fileStoreId ${resource?.filestoreId} but received ${res?.[0]?.fileStoreId}`); + throwError("COMMON", 400, "VALIDATION_ERROR", `Uploaded file doesn't match for resource of type ${resource.type}.`) + } + } + else { + logger.error(`No resource data found for resource with Id ${resource?.resourceId}`); + throwError("COMMON", 400, "VALIDATION_ERROR", `No resource data found for validation of resource type ${resource.type}.`); + } + } + } +} + +async function validateProjectCampaignResources(resources: any, request: any) { + const requiredTypes = ["user", "facility", "boundaryWithTarget"]; + const typeCounts: any = { + "user": 0, + "facility": 0, + "boundaryWithTarget": 0 + }; + + const missingTypes: string[] = []; + + if (!resources || !Array.isArray(resources) || resources.length === 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", "resources should be a non-empty array"); + } + + for (const resource of resources) { + const { type } = resource; + if (!type || !requiredTypes.includes(type)) { + throwError( + "COMMON", + 400, + "VALIDATION_ERROR", + `Invalid resource type. Allowed types are: ${requiredTypes.join(', ')}` + ); + } + typeCounts[type]++; + } + + for (const type of requiredTypes) { + if (typeCounts[type] === 0) { + missingTypes.push(type); + } + } + + if (missingTypes.length > 0) { + const missingTypesMessage = `Missing resources of types: ${missingTypes.join(', ')}`; + throwError("COMMON", 400, "VALIDATION_ERROR", missingTypesMessage); + } + + if (request?.body?.CampaignDetails?.action === "create" && request?.body?.CampaignDetails?.resources) { + await validateResources(request.body.CampaignDetails.resources, request); + } +} + + + + +function validateProjectCampaignMissingFields(CampaignDetails: any) { + validateCampaignBodyViaSchema(campaignDetailsSchema, CampaignDetails) + const { startDate, endDate } = CampaignDetails; + if (startDate && endDate && (new Date(endDate).getTime() - new Date(startDate).getTime()) < (24 * 60 * 60 * 1000)) { + throwError("COMMON", 400, "VALIDATION_ERROR", "endDate must be at least one day after startDate"); + } + const today: any = Date.now(); + if (startDate <= today) { + throwError("COMMON", 400, "VALIDATION_ERROR", "startDate cannot be today or past date"); + } +} + +function validateDraftProjectCampaignMissingFields(CampaignDetails: any) { + validateCampaignBodyViaSchema(campaignDetailsDraftSchema, CampaignDetails) + const { startDate, endDate, 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"); + } + const today: any = Date.now(); + if (startDate <= today) { + throwError("COMMON", 400, "VALIDATION_ERROR", "startDate cannot be today or past date"); + } + } +} + +async function validateCampaignName(request: any, actionInUrl: any) { + const CampaignDetails = request.body.CampaignDetails; + const { campaignName, tenantId } = CampaignDetails; + if (!campaignName) { + throwError("COMMON", 400, "VALIDATION_ERROR", "campaignName is required"); + } + if (!tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is required"); + } + if (campaignName.length >= 2) { + const searchBody = { + RequestInfo: request.body.RequestInfo, + CampaignDetails: { + tenantId: tenantId, + campaignName: campaignName + } + } + const req: any = replicateRequest(request, searchBody) + const searchResponse: any = await searchProjectTypeCampaignService(req) + if (Array.isArray(searchResponse?.CampaignDetails)) { + if (searchResponse?.CampaignDetails?.length > 0) { + const allCampaigns = searchResponse?.CampaignDetails; + logger.info(`campaignName to match : ${"'"}${campaignName}${"'"}`) + const campaignWithMatchingName: any = allCampaigns.find((campaign: any) => "'" + campaign?.campaignName + "'" == "'" + campaignName + "'") || null; + if (campaignWithMatchingName && actionInUrl == "create") { + throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_ERROR"); + } + else if (campaignWithMatchingName && actionInUrl == "update" && campaignWithMatchingName?.id != CampaignDetails?.id) { + throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_ERROR"); + } + } + } + else { + throwError("CAMPAIGN", 500, "CAMPAIGN_SEARCH_ERROR"); + } + } +} + +async function validateById(request: any) { + const { id, tenantId, action } = request?.body?.CampaignDetails + if (!id) { + throwError("COMMON", 400, "VALIDATION_ERROR", "id is required"); + } + const searchBody = { + RequestInfo: request.body.RequestInfo, + CampaignDetails: { + tenantId: tenantId, + ids: [id] + } + } + const req: any = replicateRequest(request, searchBody) + const searchResponse: any = await searchProjectTypeCampaignService(req) + if (Array.isArray(searchResponse?.CampaignDetails)) { + if (searchResponse?.CampaignDetails?.length > 0) { + logger.debug(`CampaignDetails : ${getFormattedStringForDebug(searchResponse?.CampaignDetails)}`); + request.body.ExistingCampaignDetails = searchResponse?.CampaignDetails[0]; + if (action != "changeDates") { + if (request.body.ExistingCampaignDetails?.status != campaignStatuses?.drafted) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Campaign can only be updated in drafted state. Change action to changeDates if you want to just update date.`); + } + } + } + else { + throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND"); + } + } + else { + throwError("CAMPAIGN", 500, "CAMPAIGN_SEARCH_ERROR"); + } +} + +async function validateProjectType(request: any, projectType: any, tenantId: any) { + if (!projectType) { + throwError("COMMON", 400, "VALIDATION_ERROR", "projectType is required"); + } + else { + const searchBody = { + RequestInfo: request.body.RequestInfo, + "MdmsCriteria": { + "tenantId": tenantId, + "moduleDetails": [ + { + "moduleName": "HCM-PROJECT-TYPES", + "masterDetails": [ + { + "name": "projectTypes", + "filter": "*.code" + } + ] + } + ] + } + } + const params = { tenantId: tenantId } + const searchResponse: any = await httpRequest(config.host.mdms + config?.paths?.mdms_search, searchBody, params); + if (searchResponse?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes && Array.isArray(searchResponse?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes)) { + const projectTypes = searchResponse?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes; + if (!projectTypes.includes(projectType)) { + throwError("COMMON", 400, "VALIDATION_ERROR", "projectType is not valid"); + } + } + else { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Error occured during projectType search"); + } + } +} + +function isObjectOrArray(value: any) { + return typeof value === 'object' || Array.isArray(value); +} + +async function validateChangeDatesRequest(request: any) { + var ExistingCampaignDetails = request?.body?.ExistingCampaignDetails; + const { startDate: exsistingStartDate, endDate: exsistingEndDate } = ExistingCampaignDetails; + var newCampaignDetails = request?.body?.CampaignDetails; + const { startDate: newStartDate, endDate: newEndDate } = newCampaignDetails; + + for (const key in newCampaignDetails) { + if (!isObjectOrArray(newCampaignDetails[key])) { + // If the value is not an object or array, compare it with the corresponding value in ExistingCampaignDetails + if (!(key == "startDate" || key == "endDate" || key == "action") && newCampaignDetails[key] !== ExistingCampaignDetails[key]) { + // Handle the validation failure (for example, throw an error or log a message) + throwError("COMMON", 400, "VALIDATION_ERROR", `${key} value in request campaign is not matching with existing campaign`); + } + } + } + const today: any = Date.now(); + if (exsistingStartDate <= today) { + if (exsistingStartDate != newStartDate) { + throwError("COMMON", 400, "VALIDATION_ERROR", "StartDate cannot be updated for ongoing or completed campaign."); + } + } + if (exsistingEndDate < today) { + if (exsistingEndDate != newEndDate) { + throwError("COMMON", 400, "VALIDATION_ERROR", "EndDate cannot be updated as campaign is completed."); + } + } + request.body.CampaignDetails = ExistingCampaignDetails; + request.body.CampaignDetails.action = "changeDates"; + request.body.CampaignDetails.startDate = newStartDate; + request.body.CampaignDetails.endDate = newEndDate; +} + +async function validateCampaignBody(request: any, CampaignDetails: any, actionInUrl: any) { + const { hierarchyType, action, tenantId, boundaries, resources, projectType } = CampaignDetails; + if (action == "changeDates") { + await validateChangeDatesRequest(request); + } + else if (action == "create") { + validateProjectCampaignMissingFields(CampaignDetails); + await validateCampaignName(request, actionInUrl); + if (tenantId != request?.body?.RequestInfo?.userInfo?.tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is not matching with userInfo"); + } + await validateHierarchyType(request, hierarchyType, tenantId); + await validateProjectType(request, projectType, tenantId); + await validateProjectCampaignBoundaries(boundaries, hierarchyType, tenantId, request); + await validateProjectCampaignResources(resources, request); + } + else { + validateDraftProjectCampaignMissingFields(CampaignDetails); + await validateCampaignName(request, actionInUrl); + await validateHierarchyType(request, hierarchyType, tenantId); + await validateProjectType(request, projectType, tenantId); + } +} + +async function validateProjectCampaignRequest(request: any, actionInUrl: any) { + const CampaignDetails = request.body.CampaignDetails; + const { id, action } = CampaignDetails; + if (actionInUrl == "update") { + if (!id) { + throwError("COMMON", 400, "VALIDATION_ERROR", "id is required for update"); + } + } + if (!CampaignDetails) { + throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails is required"); + } + if (!action) { + throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails.action is required and must be either 'create' or 'draft'") + } + if (!(action == "create" || action == "draft" || action == "changeDates")) { + throwError("COMMON", 400, "VALIDATION_ERROR", "action can only be create, draft or changeDates"); + } + if (actionInUrl == "update") { + await validateById(request); + } + if (action == "changeDates" && actionInUrl == "create") { + throwError("COMMON", 400, "VALIDATION_ERROR", "changeDates is not allowed during create"); + } + await validateCampaignBody(request, CampaignDetails, actionInUrl); +} + +async function validateSearchProjectCampaignRequest(request: any) { + const CampaignDetails = request.body.CampaignDetails; + if (!CampaignDetails) { + throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails is required"); + } + validateBodyViaSchema(searchCampaignDetailsSchema, CampaignDetails); + let count = 0; + let validFields = ["ids", "startDate", "endDate", "projectType", "campaignName", "status", "createdBy", "campaignNumber"]; + for (const key in CampaignDetails) { + if (key !== 'tenantId') { + if (validFields.includes(key)) { + count++; + } + } + } + if (count === 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", "At least one more field other than tenantID is required"); + } +} + +async function validateSearchRequest(request: any) { + const { SearchCriteria } = request.body; + if (!SearchCriteria) { + throwError("COMMON", 400, "VALIDATION_ERROR", "SearchCriteria is required"); + } + validateBodyViaSchema(searchCriteriaSchema, SearchCriteria); +} + + +async function validateFilters(request: any, boundaryData: any[]) { + // boundaries should be present under filters object + if (!request?.body?.Filters?.boundaries) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Invalid Filter Criteria: 'boundaries' should be present under filters "); + } + const boundaries = request?.body?.Filters?.boundaries; + // boundaries should be an array and not empty + if (!Array.isArray(boundaries) || boundaries?.length == 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Invalid Filter Criteria: 'boundaries' should be an array and should not be empty."); + } + + const boundaryMap = new Map(); + // map boundary code and type + createBoundaryMap(boundaryData, boundaryMap); + const hierarchy = await getHierarchy(request, request?.query?.tenantId, request?.query?.hierarchyType); + // validation of filters object + validateBoundariesOfFilters(boundaries, boundaryMap, hierarchy); + + const rootBoundaries = boundaries.filter((boundary: any) => boundary.isRoot); + + if (rootBoundaries.length !== 1) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Invalid Filter Criteria: Exactly one root boundary can be there, but found "${rootBoundaries.length}`); + } + + const boundaryTypeOfRoot = rootBoundaries[0]?.boundaryType; + + const boundariesOfTypeOfSameAsRoot = boundaries.filter((boundary: any) => boundary.boundaryType === boundaryTypeOfRoot); + + if (boundariesOfTypeOfSameAsRoot.length > 1) { + throwError("COMMON", 400, "VALIDATION_ERROR", `"Invalid Filter Criteria: Multiple boundaries of the same type as the root found. Only one is allowed.`); + } +} + +function validateBoundariesOfFilters(boundaries: any[], boundaryMap: Map, hierarchy: any) { + for (const boundary of boundaries) { + if (!boundary.code) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary Code is null or empty or undefined in Filters of Request Body"); + } + if (!boundary.boundaryType) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary Type is null or empty or undefined in Filters of Request Body"); + } + if (typeof boundary.isRoot !== 'boolean') { + throwError("COMMON", 400, "VALIDATION_ERROR", `isRoot can only be true or false. It is invalid for '${boundary.code}'`); + } + if (typeof boundary.includeAllChildren !== 'boolean') { + throwError("COMMON", 400, "VALIDATION_ERROR", `includeAllChildren can only be true or false. It is invalid for '${boundary.code}'`); + } + if (!boundaryMap.has(boundary?.code)) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary data with code '${boundary.code}' specified in 'Filters' of the request body was not found for the given hierarchy.`); + } + if (!hierarchy.includes(boundary?.boundaryType)) { + throwError("COMMON", 400, "VALIDATION_ERROR", `${boundary.boundaryType} boundary Type not found for given hierachy`); + } + if (boundaryMap.get(boundary.code) !== boundary.boundaryType) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary type mismatch for code '${boundary.code}' specified in 'Filters' of the request body. Expected type: ${boundaryMap.get(boundary.code)}, but found a different type.`); + } + } +} + + + + +async function validateHeaders(hierarchy: any[], headersOfBoundarySheet: any, request: any, localizationMap?: any) { + validateBoundarySheetHeaders(headersOfBoundarySheet, hierarchy, request, localizationMap); +} +function validateBoundarySheetHeaders(headersOfBoundarySheet: any[], hierarchy: any[], request: any, localizationMap?: any) { + const localizedBoundaryCode = getLocalizedName(getBoundaryColumnName(), localizationMap) + const boundaryCodeIndex = headersOfBoundarySheet.indexOf(localizedBoundaryCode); + const keysBeforeBoundaryCode = boundaryCodeIndex === -1 ? headersOfBoundarySheet : headersOfBoundarySheet.slice(0, boundaryCodeIndex); + if (keysBeforeBoundaryCode.some((key: any, index: any) => (key === undefined || key === null) || key !== hierarchy[index]) || keysBeforeBoundaryCode.length !== hierarchy.length) { + const errorMessage = `"Boundary Sheet Headers are not the same as the hierarchy present for the given tenant and hierarchy type: ${request?.body?.ResourceDetails?.hierarchyType}"`; + throwError("BOUNDARY", 400, "BOUNDARY_SHEET_HEADER_ERROR", errorMessage); + } +} + + + + +async function validateDownloadRequest(request: any) { + const { tenantId, hierarchyType } = request.query; + validateBodyViaSchema(downloadRequestSchema, request.query); + if (tenantId != request?.body?.RequestInfo?.userInfo?.tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId in userInfo and query should be the same"); + } + await validateHierarchyType(request, hierarchyType, tenantId); +} + +async function immediateValidationForTargetSheet(request: any, dataFromSheet: any, differentTabsBasedOnLevel: any, localizationMap: any) { + logger.info("validating all district tabs present started") + validateAllDistrictTabsPresentOrNot(request, dataFromSheet, differentTabsBasedOnLevel, localizationMap); + logger.info("validation of all district tabs present completed") + for (const key in dataFromSheet) { + if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { + if (Object.prototype.hasOwnProperty.call(dataFromSheet, key)) { + const dataArray = (dataFromSheet as { [key: string]: any[] })[key]; + if (dataArray.length === 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", `The Target Sheet ${key} you have uploaded is empty`) + } + const root = getLocalizedName(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 (!boundaryRow[root]) { + throwError("COMMON", 400, "VALIDATION_ERROR", ` ${root} column is empty in Target Sheet ${key} at row number ${boundaryRow['!row#number!']}`); + } + } + } + } + } +} + + +function validateAllDistrictTabsPresentOrNot(request: any, dataFromSheet: any, differentTabsBasedOnLevel: any, localizationMap?: any) { + let tabsIndex = 2; + logger.info("target sheet getting validated for different districts"); + 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 (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 `) + } else { + for (let index = tabsIndex; index < tabsFromTargetSheet.length; index++) { + const tab = tabsFromTargetSheet[index]; // Get the current tab + if (!tabsOfDistrict.includes(tab)) { + throwError("COMMON", 400, "VALIDATION_ERROR", `${differentTabsBasedOnLevel} tab ${tab} not present in the Target Sheet Uploaded`); + } + } + } + +} + +function validateSearchProcessTracksRequest(request: any) { + if (!request?.query?.campaignId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignId is required in params"); + } +} + + +export { + fetchBoundariesInChunks, + validateSheetData, + validateCreateRequest, + validateFacilityCreateData, + validateProjectCampaignRequest, + validateSearchProjectCampaignRequest, + validateSearchRequest, + validateFilters, + validateHierarchyType, + validateBoundarySheetData, + validateDownloadRequest, + validateTargetSheetData, + immediateValidationForTargetSheet, + validateBoundaryOfResouces, + validateSearchProcessTracksRequest +} diff --git a/health-services/project-factory/src/server/validators/genericValidator.ts b/health-services/project-factory/src/server/validators/genericValidator.ts new file mode 100644 index 00000000000..245579d6134 --- /dev/null +++ b/health-services/project-factory/src/server/validators/genericValidator.ts @@ -0,0 +1,261 @@ +// Importing necessary modules +import * as express from "express"; +import { logger } from "../utils/logger"; +import Ajv from "ajv"; +import config from "../config/index"; +import { httpRequest } from "../utils/request"; +import { getBoundaryRelationshipData, throwError } from "../utils/genericUtils"; +import { validateFilters } from "./campaignValidators"; +import { generateRequestSchema } from "../config/models/generateRequestSchema"; +import { persistTrack } from "../utils/processTrackUtils"; +import { processTrackTypes, processTrackStatuses, campaignStatuses } from "../config/constants"; +import { validateMappingId } from "../utils/campaignMappingUtils"; + +// Function to validate data against a JSON schema +function validateDataWithSchema(data: any, schema: any): { isValid: boolean; error: any | null | undefined } { + const ajv = new Ajv({ strict: false }); + const validate = ajv.compile(schema); + const isValid: any = validate(data); + if (!isValid) { + logger.error(JSON.stringify(validate.errors)); + } + return { isValid, error: validate.errors }; +} +function validateCampaignBodyViaSchema(schema: any, objectData: any) { + const ajv = new Ajv({ strict: false }); + const validate = ajv.compile(schema); + const isValid = validate(objectData); + if (!isValid) { + const formattedError = validate?.errors?.map((error: any) => { + let formattedErrorMessage = ""; + if (error?.dataPath) { + // Replace slash with dot and remove leading dot if present + const dataPath = error.dataPath.replace(/\//g, '.').replace(/^\./, ''); + formattedErrorMessage = `${dataPath} ${error.message}`; + } + else 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}` + } + if (error.keyword === 'enum' && error.params && error.params.allowedValues) { + formattedErrorMessage += `. Allowed values are: ${error.params.allowedValues.join(', ')}`; + } + if (error.keyword === 'additionalProperties' && error.params && error.params.additionalProperty) { + formattedErrorMessage += `, Additional property '${error.params.additionalProperty}' found.`; + } + // Capitalize the first letter of the error message + formattedErrorMessage = formattedErrorMessage.charAt(0).toUpperCase() + formattedErrorMessage.slice(1); + return formattedErrorMessage; + }).join("; "); + console.error(formattedError); + throwError("COMMON", 400, "VALIDATION_ERROR", formattedError); + } +} + +function validateBodyViaSchema(schema: any, objectData: any) { + const properties: any = { jsonPointers: true, allowUnknownAttributes: true, strict: false } + const ajv = new Ajv(properties); + const validate = ajv.compile(schema); + const isValid = validate(objectData); + if (!isValid) { + const formattedError = validate?.errors?.map((error: any) => { + let formattedErrorMessage = ""; + if (error?.dataPath) { + // Replace slash with dot and remove leading dot if present + const dataPath = error.dataPath.replace(/\//g, '.').replace(/^\./, ''); + formattedErrorMessage = `${dataPath} ${error.message}`; + } + else 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}` + } + if (error.keyword === 'enum' && error.params && error.params.allowedValues) { + formattedErrorMessage += `. Allowed values are: ${error.params.allowedValues.join(', ')}`; + } + if (error.keyword === 'additionalProperties' && error.params && error.params.additionalProperty) { + formattedErrorMessage += `, Additional property '${error.params.additionalProperty}' found.`; + } + // Capitalize the first letter of the error message + formattedErrorMessage = formattedErrorMessage.charAt(0).toUpperCase() + formattedErrorMessage.slice(1); + return formattedErrorMessage; + }).join("; "); + console.error(formattedError); + throwError("COMMON", 400, "VALIDATION_ERROR", formattedError); + } +} + +// Function to validate the resources associated with a campaign +async function validateProjectResource(requestBody: any) { + for (const campaignDetails of requestBody?.Campaign?.CampaignDetails) { + for (const resource of campaignDetails?.resources) { + const type = resource?.type; + for (const resourceId of resource?.resourceIds) { + // Check if resource type and ID are provided + if (!type) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Enter Type In Resources"); + } + if (!resourceId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Enter ResourceId In Resources of type " + type); + } + // Validate the resource ID based on its type + // await validateResourceId(type, resourceId, requestBody); + } + } + } +} + +// Function to validate the campaign details including resource validation +async function validateCampaign(requestBody: any) { + const id = requestBody?.Campaign?.id + if (!id) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Enter id of campaign for mapping"); + } + for (const campaignDetails of requestBody?.Campaign?.CampaignDetails) { + var { startDate, endDate } = campaignDetails; + startDate = parseInt(startDate); + endDate = parseInt(endDate); + } + await validateProjectResource(requestBody) +} + +// Function to validate the entire campaign request +async function validateCampaignRequest(requestBody: any) { + 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"); + } + } + 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 +function validatedProjectResponseAndUpdateId(projectResponse: any, projectBody: any, campaignDetails: any) { + if (projectBody?.Projects?.length != projectResponse?.Project?.length) { + throwError("PROJECT", 500, "PROJECT_CREATION_ERROR"); + } else { + for (const project of projectResponse?.Project) { + if (!project?.id) { + throwError("PROJECT", 500, "PROJECT_CREATION_ERROR"); + } else { + campaignDetails.projectId = project.id; + } + } + } +} + +// Function to validate project staff response +// function validateStaffResponse(staffResponse: any) { +// if (!staffResponse?.ProjectStaff?.id) { +// throwError("CAMPAIGN", 500, "RESOURCE_CREATION_ERROR", "Project staff creation failed."); +// } +// } + +// Function to validate project resource response +// function validateProjectResourceResponse(projectResouceResponse: any) { +// if (!projectResouceResponse?.ProjectResource?.id) { +// throwError("CAMPAIGN", 500, "RESOURCE_CREATION_ERROR", "Project Resource creation failed."); +// } +// } + +// Function to validate project facility response +// function validateProjectFacilityResponse(projectFacilityResponse: any) { +// if (!projectFacilityResponse?.ProjectFacility?.id) { +// throwError("CAMPAIGN", 500, "RESOURCE_CREATION_ERROR", "Project Facility creation failed."); +// } +// } + +// Function to validate the hierarchy type +async function validateHierarchyType(request: any, hierarchyType: any, tenantId: any) { + const searchBody = { + RequestInfo: request?.body?.RequestInfo, + BoundaryTypeHierarchySearchCriteria: { + "tenantId": tenantId, + "limit": 5, + "offset": 0, + "hierarchyType": hierarchyType + } + } + const response = await httpRequest(config.host.boundaryHost + config.paths.boundaryHierarchy, searchBody); + if (response?.BoundaryHierarchy && Array.isArray(response?.BoundaryHierarchy) && response?.BoundaryHierarchy?.length > 0) { + logger.info(`hierarchyType : ${hierarchyType} :: got validated`); + } + else { + throwError(`CAMPAIGN`, 400, "VALIDATION_ERROR", `hierarchyType ${hierarchyType} not found`); + } +} + +// Function to validate the generation request +async function validateGenerateRequest(request: express.Request) { + const { tenantId, hierarchyType, forceUpdate } = request.query; + validateBodyViaSchema(generateRequestSchema, request.query); + if (tenantId != request?.body?.RequestInfo?.userInfo?.tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId in userInfo and query should be the same"); + } + if (!forceUpdate) { + request.query.forceUpdate = "false"; + } + await validateHierarchyType(request, hierarchyType, tenantId); +} + +export async function validateFiltersInRequestBody(request: any) { + if (request?.body?.Filters === undefined) { + throwError("COMMON", 400, "VALIDATION_ERROR", "For type boundary Filters Object should be present in request body") + } + const params = { + ...request?.query, + includeChildren: true + }; + const boundaryData = await getBoundaryRelationshipData(request, params); + if (boundaryData && request?.body?.Filters != null) { + await validateFilters(request, boundaryData); + } +} + +export { + validateDataWithSchema, + validateBodyViaSchema, + validateCampaignRequest, + validatedProjectResponseAndUpdateId, + // validateStaffResponse, + // validateProjectFacilityResponse, + // validateProjectResourceResponse, + validateGenerateRequest, + validateHierarchyType, + validateCampaignBodyViaSchema +}; diff --git a/health-services/project-factory/src/tsconfig.json b/health-services/project-factory/src/tsconfig.json new file mode 100644 index 00000000000..6e8f96dc26c --- /dev/null +++ b/health-services/project-factory/src/tsconfig.json @@ -0,0 +1,66 @@ +{ + "compilerOptions": { + "skipLibCheck": true, + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./dist/", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + "strictNullChecks": true, /* Enable strict null checks. */ + "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + /* Additional Checks */ + "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + /* Module Resolution Options */ + "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + "typeRoots": ["node_modules/@types"], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + /* Source Map Options */ + // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + }, + "include": [ + "./**/*" + ], + "exclude": [ + "node_modules", + "**/*.test.ts" + ] +} \ No newline at end of file diff --git a/health-services/project-factory/tsconfig.json b/health-services/project-factory/tsconfig.json new file mode 100644 index 00000000000..5afabc37a6b --- /dev/null +++ b/health-services/project-factory/tsconfig.json @@ -0,0 +1,66 @@ +{ + "compilerOptions": { + "skipLibCheck": true, + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./dist/", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + "strictNullChecks": true, /* Enable strict null checks. */ + "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + /* Additional Checks */ + "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + /* Module Resolution Options */ + "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + "typeRoots": ["./node_modules/@types"], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + /* Source Map Options */ + // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + }, + "include": [ + "./src/**/*" + ], + "exclude": [ + "node_modules", + "**/*.test.ts" + ] +} \ No newline at end of file diff --git a/health-services/project-factory/yarn.lock b/health-services/project-factory/yarn.lock new file mode 100644 index 00000000000..4e9c73bf0f7 --- /dev/null +++ b/health-services/project-factory/yarn.lock @@ -0,0 +1,5666 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.2.0": + version "2.3.0" + resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.2": + version "7.24.2" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz" + integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== + dependencies: + "@babel/highlight" "^7.24.2" + picocolors "^1.0.0" + +"@babel/compat-data@^7.23.5": + version "7.24.4" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz" + integrity sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ== + +"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9", "@babel/core@^7.8.0": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz" + integrity sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.24.2" + "@babel/generator" "^7.24.5" + "@babel/helper-compilation-targets" "^7.23.6" + "@babel/helper-module-transforms" "^7.24.5" + "@babel/helpers" "^7.24.5" + "@babel/parser" "^7.24.5" + "@babel/template" "^7.24.0" + "@babel/traverse" "^7.24.5" + "@babel/types" "^7.24.5" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.24.5", "@babel/generator@^7.7.2": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz" + integrity sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA== + dependencies: + "@babel/types" "^7.24.5" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^2.5.1" + +"@babel/helper-compilation-targets@^7.23.6": + version "7.23.6" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz" + integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== + dependencies: + "@babel/compat-data" "^7.23.5" + "@babel/helper-validator-option" "^7.23.5" + browserslist "^4.22.2" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== + +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== + dependencies: + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-imports@^7.24.3": + version "7.24.3" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz" + integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== + dependencies: + "@babel/types" "^7.24.0" + +"@babel/helper-module-transforms@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz" + integrity sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.24.3" + "@babel/helper-simple-access" "^7.24.5" + "@babel/helper-split-export-declaration" "^7.24.5" + "@babel/helper-validator-identifier" "^7.24.5" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.8.0": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz" + integrity sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ== + +"@babel/helper-simple-access@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz" + integrity sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ== + dependencies: + "@babel/types" "^7.24.5" + +"@babel/helper-split-export-declaration@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz" + integrity sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q== + dependencies: + "@babel/types" "^7.24.5" + +"@babel/helper-string-parser@^7.24.1": + version "7.24.1" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz" + integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== + +"@babel/helper-validator-identifier@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz" + integrity sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA== + +"@babel/helper-validator-option@^7.23.5": + version "7.23.5" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz" + integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== + +"@babel/helpers@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz" + integrity sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q== + dependencies: + "@babel/template" "^7.24.0" + "@babel/traverse" "^7.24.5" + "@babel/types" "^7.24.5" + +"@babel/highlight@^7.24.2": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz" + integrity sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw== + dependencies: + "@babel/helper-validator-identifier" "^7.24.5" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz" + integrity sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.24.1" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz" + integrity sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.24.1" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz" + integrity sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3": + version "7.24.0" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz" + integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== + dependencies: + "@babel/code-frame" "^7.23.5" + "@babel/parser" "^7.24.0" + "@babel/types" "^7.24.0" + +"@babel/traverse@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz" + integrity sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA== + dependencies: + "@babel/code-frame" "^7.24.2" + "@babel/generator" "^7.24.5" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.24.5" + "@babel/parser" "^7.24.5" + "@babel/types" "^7.24.5" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.24.5", "@babel/types@^7.3.3": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz" + integrity sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ== + dependencies: + "@babel/helper-string-parser" "^7.24.1" + "@babel/helper-validator-identifier" "^7.24.5" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@colors/colors@^1.6.0", "@colors/colors@1.6.0": + version "1.6.0" + resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz" + integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@dabh/diagnostics@^2.0.2": + version "2.0.3" + resolved "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz" + integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA== + dependencies: + colorspace "1.1.x" + enabled "2.0.x" + kuler "^2.0.0" + +"@eslint/eslintrc@^0.2.2": + version "0.2.2" + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz" + integrity sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + lodash "^4.17.19" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@fast-csv/format@4.3.5": + version "4.3.5" + resolved "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz" + integrity sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A== + dependencies: + "@types/node" "^14.0.1" + lodash.escaperegexp "^4.1.2" + lodash.isboolean "^3.0.3" + lodash.isequal "^4.5.0" + lodash.isfunction "^3.0.9" + lodash.isnil "^4.0.0" + +"@fast-csv/parse@4.3.6": + version "4.3.6" + resolved "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz" + integrity sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA== + dependencies: + "@types/node" "^14.0.1" + lodash.escaperegexp "^4.1.2" + lodash.groupby "^4.6.0" + lodash.isfunction "^3.0.9" + lodash.isnil "^4.0.0" + lodash.isundefined "^3.0.1" + lodash.uniq "^4.5.0" + +"@ioredis/commands@^1.1.1": + version "1.2.0" + resolved "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz" + integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg== + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": + version "0.1.3" + resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== + dependencies: + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== + dependencies: + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== + dependencies: + expect "^29.7.0" + jest-snapshot "^29.7.0" + +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== + dependencies: + "@jest/types" "^29.6.3" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" + +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^6.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== + dependencies: + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== + dependencies: + "@jest/test-result" "^29.7.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + slash "^3.0.0" + +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@npmcli/agent@^2.0.0": + version "2.2.2" + resolved "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz" + integrity sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og== + dependencies: + agent-base "^7.1.0" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.1" + lru-cache "^10.0.1" + socks-proxy-agent "^8.0.3" + +"@npmcli/fs@^3.1.0": + version "3.1.1" + resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz" + 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" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@sinonjs/commons@^3.0.0": + version "3.0.1" + resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== + dependencies: + "@sinonjs/commons" "^3.0.0" + +"@tsconfig/node10@^1.0.7": + version "1.0.11" + resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + +"@types/babel__core@^7.1.14": + version "7.20.5" + resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.8" + resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz" + integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.20.5" + resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz" + integrity sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ== + dependencies: + "@babel/types" "^7.20.7" + +"@types/body-parser@*": + version "1.19.5" + resolved "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz" + integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/compression@1.7.5": + version "1.7.5" + resolved "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz" + integrity sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg== + dependencies: + "@types/express" "*" + +"@types/connect@*": + version "3.4.38" + resolved "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== + dependencies: + "@types/node" "*" + +"@types/express-serve-static-core@^4.17.33": + version "4.19.0" + resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz" + integrity sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@*", "@types/express@4.17.21": + version "4.17.21" + resolved "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz" + integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/graceful-fs@^4.1.3": + version "4.1.9" + resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== + dependencies: + "@types/node" "*" + +"@types/hash-sum@1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@types/hash-sum/-/hash-sum-1.0.2.tgz" + integrity sha512-UP28RddqY8xcU0SCEp9YKutQICXpaAq9N8U2klqF5hegGha7KzTOL8EdhIIV3bOSGBzjEpN9bU/d+nNZBdJYVw== + +"@types/helmet@0.0.47": + version "0.0.47" + resolved "https://registry.npmjs.org/@types/helmet/-/helmet-0.0.47.tgz" + integrity sha512-TcHA/djjdUtrMtq/QAayVLrsgjNNZ1Uhtz0KhfH01mrmjH44E54DA1A0HNbwW0H/NBFqV+tGMo85ACuEhMXcdg== + dependencies: + "@types/express" "*" + +"@types/http-errors@*": + version "2.0.4" + resolved "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz" + integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== + +"@types/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" + 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== + 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" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.4" + resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jaeger-client@^3.18.7": + version "3.18.7" + resolved "https://registry.npmjs.org/@types/jaeger-client/-/jaeger-client-3.18.7.tgz" + integrity sha512-ktEWbcM8faJY5UNEmffnvavjIJ9noNCD7clD9hAZIuQt6QMv0T97kiveH0mbvBNr9SPZXmkidOu/3UWgSy89tQ== + dependencies: + "@types/node" "*" + opentracing "~0.14.3" + prom-client "~11.3.0 || ^12.0.0 || ^13.0.0 || ^14.0.0" + +"@types/jest@29.5.12": + version "29.5.12" + resolved "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz" + integrity sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/lodash@^4.17.5": + version "4.17.5" + resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.5.tgz" + integrity sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw== + +"@types/mime@^1": + version "1.3.5" + resolved "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz" + integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== + +"@types/morgan@1.9.9": + version "1.9.9" + resolved "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.9.tgz" + integrity sha512-iRYSDKVaC6FkGSpEVVIvrRGw0DfJMiQzIn3qr2G5B3C//AWkulhXgaBd7tS9/J79GWSYMTHGs7PfI5b3Y8m+RQ== + dependencies: + "@types/node" "*" + +"@types/node@*", "@types/node@20.11.29": + version "20.11.29" + resolved "https://registry.npmjs.org/@types/node/-/node-20.11.29.tgz" + integrity sha512-P99thMkD/1YkCvAtOd6/zGedKNA0p2fj4ZpjCzcNiSCBWgm3cNRTBfa/qjFnsKkkojxu4vVLtWpesnZ9+ap+gA== + dependencies: + undici-types "~5.26.4" + +"@types/node@^14.0.1": + version "14.18.63" + resolved "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz" + 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" + integrity sha512-xocw4LvpDcj/Ta7bN52tLZm34mso5SZ0Q8fVC0UtD8s85Itip3YHvBeYZhBmC0OThpdOujHsxXtRbEIRxqXPXg== + dependencies: + "@types/node" "*" + pg-protocol "*" + pg-types "^4.0.1" + +"@types/qs@*": + version "6.9.15" + resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz" + integrity sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg== + +"@types/range-parser@*": + version "1.2.7" + resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz" + integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== + +"@types/send@*": + version "0.17.4" + resolved "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz" + integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/serve-static@*": + version "1.15.7" + resolved "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz" + integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== + dependencies: + "@types/http-errors" "*" + "@types/node" "*" + "@types/send" "*" + +"@types/stack-utils@^2.0.0": + version "2.0.3" + resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + +"@types/strip-bom@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz" + integrity sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ== + +"@types/strip-json-comments@0.0.30": + version "0.0.30" + resolved "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz" + integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ== + +"@types/triple-beam@^1.3.2": + version "1.3.5" + resolved "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz" + integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== + +"@types/uuid@9.0.8": + version "9.0.8" + resolved "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz" + integrity sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA== + +"@types/xlsx@0.0.36": + version "0.0.36" + resolved "https://registry.npmjs.org/@types/xlsx/-/xlsx-0.0.36.tgz" + integrity sha512-mvfrKiKKMErQzLMF8ElYEH21qxWCZtN59pHhWGmWCWFJStYdMWjkDSAy6mGowFxHXaXZWe5/TW7pBUiWclIVOw== + dependencies: + xlsx "*" + +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^17.0.8": + version "17.0.32" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz" + integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog== + dependencies: + "@types/yargs-parser" "*" + +abbrev@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz" + integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== + +accepts@~1.3.5, accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-jsx@^5.3.1: + version "5.3.2" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^8.1.1: + version "8.3.2" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz" + integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== + +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^7.4.0: + version "7.4.1" + resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.4.1: + version "8.11.3" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== + +adler-32@~1.3.0: + version "1.3.1" + resolved "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz" + integrity sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A== + +agent-base@^7.0.2, agent-base@^7.1.0, agent-base@^7.1.1: + version "7.1.1" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz" + integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== + dependencies: + debug "^4.3.4" + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv-errors@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz" + integrity sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ== + +ajv@^6.10.0: + version "6.12.6" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.1, ajv@^8.16.0: + version "8.16.0" + resolved "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz" + integrity sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw== + dependencies: + fast-deep-equal "^3.1.3" + 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" + 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" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" + integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +anymatch@^3.0.3, anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +archiver-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz" + integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw== + dependencies: + glob "^7.1.4" + graceful-fs "^4.2.0" + lazystream "^1.0.0" + lodash.defaults "^4.2.0" + lodash.difference "^4.5.0" + lodash.flatten "^4.4.0" + lodash.isplainobject "^4.0.6" + lodash.union "^4.6.0" + normalize-path "^3.0.0" + readable-stream "^2.0.0" + +archiver-utils@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz" + integrity sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw== + dependencies: + glob "^7.2.3" + graceful-fs "^4.2.0" + lazystream "^1.0.0" + lodash.defaults "^4.2.0" + lodash.difference "^4.5.0" + lodash.flatten "^4.4.0" + lodash.isplainobject "^4.0.6" + lodash.union "^4.6.0" + normalize-path "^3.0.0" + readable-stream "^3.6.0" + +archiver@^5.0.0: + version "5.3.2" + resolved "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz" + integrity sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw== + dependencies: + archiver-utils "^2.1.0" + async "^3.2.4" + buffer-crc32 "^0.2.1" + readable-stream "^3.6.0" + readdir-glob "^1.1.2" + tar-stream "^2.2.0" + zip-stream "^4.1.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" + integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +async@^2.6.2: + version "2.6.4" + resolved "https://registry.npmjs.org/async/-/async-2.6.4.tgz" + integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== + dependencies: + lodash "^4.17.14" + +async@^3.2.3: + version "3.2.5" + resolved "https://registry.npmjs.org/async/-/async-3.2.5.tgz" + integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== + +async@^3.2.4: + version "3.2.5" + resolved "https://registry.npmjs.org/async/-/async-3.2.5.tgz" + integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +axios@1.6.8: + version "1.6.8" + resolved "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz" + integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== + dependencies: + "@jest/transform" "^29.7.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.6.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== + dependencies: + babel-plugin-jest-hoist "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" + 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" + 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" + 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" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +binary@~0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz" + integrity sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg== + dependencies: + buffers "~0.1.1" + chainsaw "~0.1.0" + +bindings@^1.3.1: + version "1.5.0" + resolved "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bintrees@1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz" + integrity sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw== + +bl@^1.0.0: + version "1.2.3" + resolved "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz" + integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + +bl@^2.2.0: + version "2.2.1" + resolved "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz" + integrity sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + +bl@^4.0.3: + 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" + +bluebird@~3.4.1: + version "3.4.7" + resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz" + integrity sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA== + +body-parser@^1.20.2, body-parser@1.20.2: + version "1.20.2" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browserslist@^4.22.2, "browserslist@>= 4.21.0": + version "4.23.0" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz" + integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== + dependencies: + caniuse-lite "^1.0.30001587" + electron-to-chromium "^1.4.668" + node-releases "^2.0.14" + update-browserslist-db "^1.0.13" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-crc32@^0.2.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" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz" + integrity sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ== + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-indexof-polyfill@~1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz" + 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" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +buffermaker@~1.2.0: + version "1.2.1" + resolved "https://registry.npmjs.org/buffermaker/-/buffermaker-1.2.1.tgz" + integrity sha512-IdnyU2jDHU65U63JuVQNTHiWjPRH0CS3aYd/WPaEwyX84rFdukhOduAVb1jwUScmb5X0JWPw8NZOrhoLMiyAHQ== + dependencies: + long "1.1.2" + +buffers@~0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz" + integrity sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ== + +bufrw@^1.2.1: + version "1.4.0" + resolved "https://registry.npmjs.org/bufrw/-/bufrw-1.4.0.tgz" + integrity sha512-sWm8iPbqvL9+5SiYxXH73UOkyEbGQg7kyHQmReF89WJHQJw2eV4P/yZ0E+b71cczJ4pPobVhXxgQcmfSTgGHxQ== + dependencies: + ansi-color "^0.2.1" + error "^7.0.0" + hexer "^1.5.0" + xtend "^4.0.0" + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz" + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +cacache@^18.0.0: + version "18.0.3" + resolved "https://registry.npmjs.org/cacache/-/cacache-18.0.3.tgz" + integrity sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg== + dependencies: + "@npmcli/fs" "^3.1.0" + fs-minipass "^3.0.0" + glob "^10.2.2" + lru-cache "^10.0.1" + minipass "^7.0.3" + minipass-collect "^2.0.1" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + p-map "^4.0.0" + ssri "^10.0.0" + tar "^6.1.11" + unique-filename "^3.0.0" + +call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001587: + version "1.0.30001620" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001620.tgz" + integrity sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew== + +cfb@^1.1.3, cfb@~1.2.1: + version "1.2.2" + resolved "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz" + integrity sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA== + dependencies: + adler-32 "~1.3.0" + crc-32 "~1.2.0" + +chainsaw@~0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz" + integrity sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ== + dependencies: + traverse ">=0.3.0 <0.4" + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +chokidar@^3.5.1: + version "3.6.0" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chownr@^1.0.1: + version "1.1.4" + resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +cjs-module-lexer@^1.0.0: + version "1.3.1" + resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz" + integrity sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q== + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +clone@2.x: + version "2.1.2" + resolved "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz" + integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== + +cluster-key-slot@^1.1.0: + 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== + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz" + integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== + +codepage@~1.15.0: + version "1.15.0" + resolved "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz" + integrity sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA== + +collect-v8-coverage@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^1.9.3: + version "1.9.3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-string@^1.6.0: + version "1.9.1" + resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.1.3: + version "3.2.1" + resolved "https://registry.npmjs.org/color/-/color-3.2.1.tgz" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== + dependencies: + color-convert "^1.9.3" + color-string "^1.6.0" + +colorspace@1.1.x: + version "1.1.4" + resolved "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz" + integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== + dependencies: + color "^3.1.3" + text-hex "1.0.x" + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +compress-commons@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz" + integrity sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg== + dependencies: + buffer-crc32 "^0.2.13" + crc32-stream "^4.0.2" + normalize-path "^3.0.0" + readable-stream "^3.6.0" + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@1.7.4: + version "1.7.4" + resolved "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz" + integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz" + 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" + 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" + 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" + integrity sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw== + dependencies: + crc-32 "^1.2.0" + readable-stream "^3.4.0" + +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +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== + +debug@^2.1.3, debug@2.6.9: + version "2.6.9" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^4.0.1: + version "4.3.5" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + dependencies: + ms "2.1.2" + +debug@^4.1.0: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + 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" + +debug@^4.3.1: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^4.3.4: + version "4.3.5" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + dependencies: + ms "2.1.2" + +debug@4: + version "4.3.5" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + dependencies: + ms "2.1.2" + +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz" + integrity sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA== + dependencies: + mimic-response "^1.0.0" + +dedent@^1.0.0: + version "1.5.3" + resolved "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz" + integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@^0.1.3, deep-is@~0.1.3: + version "0.1.4" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" + integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== + +denque@^1.3.0: + version "1.5.1" + resolved "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz" + integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== + +denque@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz" + integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== + +depd@~2.0.0, depd@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz" + integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +duplexer2@~0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz" + 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" + integrity sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ== + dependencies: + xtend "^4.0.0" + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.4.668: + version "1.4.772" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.772.tgz" + integrity sha512-jFfEbxR/abTTJA3ci+2ok1NTuOBBtB4jH+UT6PUmRN+DY3WSD4FFRsgoVQ+QNIJ0T7wrXwzsWCI2WKC46b++2A== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +enabled@2.0.x: + version "2.0.0" + resolved "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz" + integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +encoding@^0.1.13: + version "0.1.13" + resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz" + integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== + dependencies: + iconv-lite "^0.6.2" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0, 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" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enquirer@^2.3.5: + version "2.4.1" + resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz" + integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== + dependencies: + ansi-colors "^4.1.1" + strip-ansi "^6.0.1" + +env-paths@^2.2.0: + version "2.2.1" + resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + +err-code@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz" + integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +error@^7.0.0, error@7.0.2: + version "7.0.2" + resolved "https://registry.npmjs.org/error/-/error-7.0.2.tgz" + integrity sha512-UtVv4l5MhijsYUxPJo4390gzfZvAnTHreNnDjnTZaKIiZ/SemXxAhBkYSKtWa5RtBXbLP8tMgn/n0RUa/H7jXw== + dependencies: + string-template "~0.2.1" + xtend "~4.0.0" + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +escalade@^3.1.1, escalade@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz" + integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escodegen@^1.8.1: + version "1.14.3" + resolved "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz" + integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== + dependencies: + esprima "^4.0.1" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.1.0: + version "1.3.0" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint@7.16.0: + version "7.16.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-7.16.0.tgz" + integrity sha512-iVWPS785RuDA4dWuhhgXTNrGxHHK3a8HLSMBgbbU59ruJDubUraXN8N5rn7kb8tG6sjg74eE0RA3YWT51eusEw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@eslint/eslintrc" "^0.2.2" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + eslint-scope "^5.1.1" + eslint-utils "^2.1.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.1" + esquery "^1.2.0" + esutils "^2.0.2" + file-entry-cache "^6.0.0" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash "^4.17.19" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^6.0.4" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^7.3.0, espree@^7.3.1: + version "7.3.1" + resolved "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz" + integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^1.3.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esprima@1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz" + integrity sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A== + +esquery@^1.2.0: + version "1.5.0" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1, estraverse@^4.2.0: + version "4.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +exceljs@4.4.0: + version "4.4.0" + resolved "https://registry.npmjs.org/exceljs/-/exceljs-4.4.0.tgz" + integrity sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg== + dependencies: + archiver "^5.0.0" + dayjs "^1.8.34" + fast-csv "^4.3.1" + jszip "^3.10.1" + readable-stream "^3.6.0" + saxes "^5.0.1" + tmp "^0.2.0" + unzipper "^0.10.11" + uuid "^8.3.0" + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expand-template@^2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz" + integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== + +expect@^29.0.0, expect@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== + dependencies: + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + +exponential-backoff@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz" + integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== + +express@^4.19.2: + version "4.19.2" + resolved "https://registry.npmjs.org/express/-/express-4.19.2.tgz" + integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.2" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.6.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +fast-csv@^4.3.1: + version "4.3.6" + resolved "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz" + integrity sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw== + dependencies: + "@fast-csv/format" "4.3.5" + "@fast-csv/parse" "4.3.6" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + +fecha@^4.2.0: + version "4.2.3" + resolved "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz" + integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== + +file-entry-cache@^6.0.0: + version "6.0.1" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + +flatted@^3.2.9: + version "3.3.1" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== + +fn.name@1.x.x: + version "1.1.0" + resolved "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz" + integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== + +follow-redirects@^1.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== + +foreground-child@^3.1.0: + version "3.2.0" + resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.0.tgz" + integrity sha512-CrWQNaEl1/6WeZoarcM9LHupTo3RpZO2Pdk1vktwzPiQTsJnAKJmm3TACKeG5UZbWDfaH2AbvYxzP96y0MT7fA== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +frac@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz" + integrity sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + +fs-minipass@^3.0.0: + version "3.0.3" + resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz" + integrity sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw== + dependencies: + minipass "^7.0.3" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fstream@^1.0.12: + version "1.0.12" + resolved "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz" + integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz" + integrity sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg== + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +github-from-package@0.0.0: + version "0.0.0" + resolved "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz" + integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== + +glob-parent@^5.0.0, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^10.2.2, glob@^10.3.10: + version "10.4.1" + resolved "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz" + integrity sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + path-scurry "^1.11.1" + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.4: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.2.3: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^12.1.0: + version "12.4.0" + resolved "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz" + 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" + 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" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.0.1: + version "1.0.3" + resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz" + integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== + +hash-sum@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz" + integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg== + +hasown@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +helmet@7.1.0: + version "7.1.0" + resolved "https://registry.npmjs.org/helmet/-/helmet-7.1.0.tgz" + integrity sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg== + +hexer@^1.5.0: + version "1.5.0" + resolved "https://registry.npmjs.org/hexer/-/hexer-1.5.0.tgz" + integrity sha512-dyrPC8KzBzUJ19QTIo1gXNqIISRXQ0NwteW6OeQHRN4ZuZeHkdODfj0zHBdOlHbRY8GqbqK57C9oWSvQZizFsg== + dependencies: + ansi-color "^0.2.1" + minimist "^1.1.0" + process "^0.10.0" + xtend "^4.0.0" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +http-cache-semantics@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +http-proxy-agent@^7.0.0: + version "7.0.2" + resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz" + integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + +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== + dependencies: + "@types/http-proxy" "^1.17.10" + debug "^4.3.4" + http-proxy "^1.18.1" + is-glob "^4.0.1" + is-plain-obj "^3.0.0" + micromatch "^4.0.5" + +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + 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== + dependencies: + agent-base "^7.0.2" + debug "4" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@^0.6.2: + version "0.6.3" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" + 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" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3, inherits@2, inherits@2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@~1.3.0: + version "1.3.8" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +ioredis@^5.4.1: + 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" + +ip-address@^9.0.5: + version "9.0.5" + resolved "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz" + integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g== + dependencies: + jsbn "1.1.0" + sprintf-js "^1.1.3" + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.13.0: + version "2.13.1" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz" + integrity sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw== + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-lambda@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz" + integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-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-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isexe@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz" + integrity sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-instrument@^5.0.4: + version "5.2.1" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-instrument@^6.0.0: + version "6.0.2" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz" + integrity sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw== + dependencies: + "@babel/core" "^7.23.9" + "@babel/parser" "^7.23.9" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.7" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jackspeak@^3.1.2: + version "3.4.0" + resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz" + integrity sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +jaeger-client@^3.19.0: + version "3.19.0" + resolved "https://registry.npmjs.org/jaeger-client/-/jaeger-client-3.19.0.tgz" + integrity sha512-M0c7cKHmdyEUtjemnJyx/y9uX16XHocL46yQvyqDlPdvAcwPDbHrIbKjQdBqtiE4apQ/9dmr+ZLJYYPGnurgpw== + dependencies: + node-int64 "^0.4.0" + opentracing "^0.14.4" + thriftrw "^3.5.0" + uuid "^8.3.2" + xorshift "^1.1.1" + +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== + dependencies: + execa "^5.0.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + pretty-format "^29.7.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== + dependencies: + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + create-jest "^29.7.0" + exit "^0.1.2" + import-local "^3.0.2" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + yargs "^17.3.1" + +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== + dependencies: + "@jest/types" "^29.6.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== + dependencies: + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-util "^29.7.0" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== + +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== + dependencies: + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" + +jest-resolve@*, jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-pnp-resolver "^1.2.2" + jest-util "^29.7.0" + jest-validate "^29.7.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== + dependencies: + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.7.0" + graceful-fs "^4.2.9" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + natural-compare "^1.4.0" + pretty-format "^29.7.0" + semver "^7.5.3" + +jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== + dependencies: + "@jest/types" "^29.6.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.6.3" + leven "^3.1.0" + pretty-format "^29.7.0" + +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== + dependencies: + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.7.0" + string-length "^4.0.1" + +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== + dependencies: + "@types/node" "*" + jest-util "^29.7.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== + dependencies: + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" + import-local "^3.0.2" + jest-cli "^29.7.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz" + integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +jsonpath@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz" + integrity sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w== + dependencies: + esprima "1.2.2" + static-eval "2.0.2" + underscore "1.12.1" + +jszip@^3.10.1, jszip@^3.2.2: + version "3.10.1" + resolved "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz" + integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== + dependencies: + lie "~3.3.0" + pako "~1.0.2" + readable-stream "~2.3.6" + setimmediate "^1.0.5" + +kafka-node@5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/kafka-node/-/kafka-node-5.0.0.tgz" + integrity sha512-dD2ga5gLcQhsq1yNoQdy1MU4x4z7YnXM5bcG9SdQuiNr5KKuAmXixH1Mggwdah5o7EfholFbcNDPSVA6BIfaug== + dependencies: + async "^2.6.2" + binary "~0.3.0" + bl "^2.2.0" + buffer-crc32 "~0.2.5" + buffermaker "~1.2.0" + debug "^2.1.3" + denque "^1.3.0" + lodash "^4.17.4" + minimatch "^3.0.2" + nested-error-stacks "^2.0.0" + optional "^0.1.3" + retry "^0.10.1" + uuid "^3.0.0" + optionalDependencies: + snappy "^6.0.1" + +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +kuler@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== + +lazystream@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz" + 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" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" + integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lie@~3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz" + integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== + dependencies: + immediate "~3.0.5" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +listenercount@~1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz" + 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" + 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" + 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" + 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" + 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" + 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" + integrity sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw== + +lodash.isarguments@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz" + integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz" + 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" + 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" + 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" + 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" + 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" + 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" + 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" + 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" + integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== + +lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4, lodash@4.17.21: + version "4.17.21" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +logform@^2.3.2, logform@^2.4.0: + version "2.6.0" + resolved "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz" + integrity sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ== + dependencies: + "@colors/colors" "1.6.0" + "@types/triple-beam" "^1.3.2" + fecha "^4.2.0" + ms "^2.1.1" + safe-stable-stringify "^2.3.1" + triple-beam "^1.3.0" + +long@^2.4.0: + version "2.4.0" + resolved "https://registry.npmjs.org/long/-/long-2.4.0.tgz" + integrity sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ== + +long@1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/long/-/long-1.1.2.tgz" + integrity sha512-pjR3OP1X2VVQhCQlrq3s8UxugQsuoucwMOn9Yj/kN/61HMc+lDFJS5bvpNEHneZ9NVaSm8gNWxZvtGS7lqHb3Q== + +lru-cache@^10.0.1, lru-cache@^10.2.0: + version "10.2.2" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz" + integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +make-fetch-happen@^13.0.0: + version "13.0.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" + http-cache-semantics "^4.1.1" + is-lambda "^1.0.1" + minipass "^7.0.2" + minipass-fetch "^3.0.0" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + negotiator "^0.6.3" + 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" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micromatch@^4.0.4, 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== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +"mime-db@>= 1.43.0 < 2", mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-response@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.1.0: + version "5.1.6" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.4: + version "9.0.4" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== + 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" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +minipass-collect@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz" + integrity sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw== + dependencies: + minipass "^7.0.3" + +minipass-fetch@^3.0.0: + version "3.0.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" + minizlib "^2.1.2" + optionalDependencies: + encoding "^0.1.13" + +minipass-flush@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz" + integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== + dependencies: + minipass "^3.0.0" + +minipass-pipeline@^1.2.4: + version "1.2.4" + resolved "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz" + integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== + dependencies: + minipass "^3.0.0" + +minipass-sized@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz" + integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== + dependencies: + minipass "^3.0.0" + +minipass@^3.0.0: + version "3.3.6" + resolved "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== + dependencies: + yallist "^4.0.0" + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + +minizlib@^2.1.1, minizlib@^2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + +mkdirp@^0.5.1, "mkdirp@>=0.5 0": + version "0.5.6" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +morgan@1.10.0: + version "1.10.0" + resolved "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz" + integrity sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ== + dependencies: + basic-auth "~2.0.1" + debug "2.6.9" + depd "~2.0.0" + on-finished "~2.3.0" + on-headers "~1.0.2" + +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nan@^2.14.1: + version "2.19.0" + resolved "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz" + integrity sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw== + +napi-build-utils@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz" + integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +negotiator@^0.6.3, negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +nested-error-stacks@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz" + integrity sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw== + +node-abi@^2.7.0: + version "2.30.1" + resolved "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz" + integrity sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w== + dependencies: + semver "^5.4.1" + +node-cache@5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz" + integrity sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg== + dependencies: + clone "2.x" + +node-gyp@10.0.1: + version "10.0.1" + resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz" + integrity sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg== + dependencies: + env-paths "^2.2.0" + exponential-backoff "^3.1.1" + glob "^10.3.10" + graceful-fs "^4.2.6" + make-fetch-happen "^13.0.0" + nopt "^7.0.0" + proc-log "^3.0.0" + semver "^7.3.5" + tar "^6.1.2" + which "^4.0.0" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.14: + version "2.0.14" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz" + integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== + +noop-logger@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz" + integrity sha512-6kM8CLXvuW5crTxsAtva2YLrRrDaiTIkIePWs9moLHqbFWT94WpNFjwS/5dfLfECg5i/lkmw3aoqVidxt23TEQ== + +nopt@^7.0.0: + version "7.2.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" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +npmlog@^4.0.1: + version "4.1.2" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz" + integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== + +object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.13.1: + version "1.13.1" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + +obuf@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz" + integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== + dependencies: + ee-first "1.1.1" + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +one-time@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz" + integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== + dependencies: + fn.name "1.x.x" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +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" + 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" + integrity sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw== + +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +optionator@^0.9.1: + version "0.9.4" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + 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" + +os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz" + integrity sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ== + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +pako@~1.0.2: + version "1.0.11" + resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + +pg-cloudflare@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz" + integrity sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q== + +pg-connection-string@^2.6.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== + +pg-int8@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz" + integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== + +pg-numeric@1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz" + integrity sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw== + +pg-pool@^3.6.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== + +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== + +pg-types@^2.1.0: + version "2.2.0" + resolved "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz" + integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== + dependencies: + pg-int8 "1.0.1" + postgres-array "~2.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.4" + postgres-interval "^1.1.0" + +pg-types@^4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz" + integrity sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng== + dependencies: + pg-int8 "1.0.1" + pg-numeric "1.0.2" + postgres-array "~3.0.1" + postgres-bytea "~3.0.0" + postgres-date "~2.1.0" + postgres-interval "^3.0.0" + postgres-range "^1.1.1" + +pg@>=8.0, pg@8.12.0: + version "8.12.0" + resolved "https://registry.npmjs.org/pg/-/pg-8.12.0.tgz" + integrity sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ== + dependencies: + pg-connection-string "^2.6.4" + pg-pool "^3.6.2" + pg-protocol "^1.6.1" + pg-types "^2.1.0" + pgpass "1.x" + optionalDependencies: + pg-cloudflare "^1.1.1" + +pgpass@1.x: + version "1.0.5" + resolved "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz" + integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug== + dependencies: + split2 "^4.1.0" + +picocolors@^1.0.0, picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pirates@^4.0.4: + version "4.0.6" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +postgres-array@~2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz" + integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== + +postgres-array@~3.0.1: + version "3.0.2" + resolved "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz" + integrity sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog== + +postgres-bytea@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz" + integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w== + +postgres-bytea@~3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz" + integrity sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw== + dependencies: + obuf "~1.1.2" + +postgres-date@~1.0.4: + version "1.0.7" + resolved "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz" + integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== + +postgres-date@~2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz" + integrity sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA== + +postgres-interval@^1.1.0: + version "1.2.0" + resolved "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz" + integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== + dependencies: + xtend "^4.0.0" + +postgres-interval@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz" + integrity sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw== + +postgres-range@^1.1.1: + version "1.1.4" + resolved "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz" + integrity sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w== + +prebuild-install@5.3.0: + version "5.3.0" + resolved "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.0.tgz" + integrity sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg== + dependencies: + detect-libc "^1.0.3" + expand-template "^2.0.3" + github-from-package "0.0.0" + minimist "^1.2.0" + mkdirp "^0.5.1" + napi-build-utils "^1.0.1" + node-abi "^2.7.0" + noop-logger "^0.1.1" + npmlog "^4.0.1" + os-homedir "^1.0.1" + pump "^2.0.1" + rc "^1.2.7" + simple-get "^2.7.0" + tar-fs "^1.13.0" + tunnel-agent "^0.6.0" + which-pm-runs "^1.0.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" + integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== + +pretty-format@^29.0.0, pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +proc-log@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz" + integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A== + +proc-log@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz" + integrity sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" + 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" + 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" + 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" + 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" + integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== + dependencies: + err-code "^2.0.2" + retry "^0.12.0" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +property-expr@^2.0.5: + version "2.0.6" + resolved "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz" + integrity sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA== + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +pump@^1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz" + integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +pure-rand@^6.0.0: + version "6.1.0" + resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== + +qs@6.11.0: + version "6.11.0" + resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +react-is@^18.0.0: + version "18.3.1" + resolved "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + +readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@~2.3.6: + version "2.3.8" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdir-glob@^1.1.2: + version "1.1.3" + resolved "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz" + 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" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz" + integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w== + +redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz" + integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A== + dependencies: + redis-errors "^1.0.0" + +regexpp@^3.1.0: + version "3.2.0" + resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" + 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" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== + +resolve@^1.0.0, resolve@^1.20.0: + version "1.22.8" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +retry@^0.10.1: + version "0.10.1" + resolved "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz" + integrity sha512-ZXUSQYTHdl3uS7IuCehYfMzKyIDBNoAuUblvy5oGO5UJSUTmStUUVPXbA9Qxd173Bgre53yCQczQuHgRWAdvJQ== + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== + +rimraf@^2.6.1: + version "2.7.1" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rimraf@2: + version "2.7.1" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1, safe-buffer@5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1: + version "5.2.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-stable-stringify@^2.3.1: + version "2.4.3" + resolved "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz" + integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sax@^1.2.4: + version "1.3.0" + resolved "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz" + integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA== + +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz" + 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" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@^6.3.0: + version "6.3.1" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.2.1: + version "7.6.2" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + +semver@^7.3.5: + version "7.6.2" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + +semver@^7.5.3: + version "7.6.2" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + +semver@^7.5.4: + version "7.6.2" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + +send@0.18.0: + version "0.18.0" + resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +setimmediate@^1.0.5, setimmediate@~1.0.4: + version "1.0.5" + resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + +signal-exit@^3.0.0, signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + +simple-get@^2.7.0: + version "2.8.2" + resolved "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz" + integrity sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw== + dependencies: + decompress-response "^3.3.0" + once "^1.3.1" + simple-concat "^1.0.0" + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + +snappy@^6.0.1: + version "6.3.5" + resolved "https://registry.npmjs.org/snappy/-/snappy-6.3.5.tgz" + integrity sha512-lonrUtdp1b1uDn1dbwgQbBsb5BbaiLeKq+AGwOk2No+en+VvJThwmtztwulEQsLinRF681pBqib0NUZaizKLIA== + dependencies: + bindings "^1.3.1" + nan "^2.14.1" + prebuild-install "5.3.0" + +socks-proxy-agent@^8.0.3: + version "8.0.3" + resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz" + integrity sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A== + dependencies: + agent-base "^7.1.1" + debug "^4.3.4" + socks "^2.7.1" + +socks@^2.7.1: + version "2.8.3" + resolved "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz" + integrity sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw== + dependencies: + ip-address "^9.0.5" + smart-buffer "^4.2.0" + +source-map-support@^0.5.12, source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +split2@^4.1.0: + version "4.2.0" + resolved "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== + +sprintf-js@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz" + integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +ssf@~0.11.2: + version "0.11.2" + resolved "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz" + integrity sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g== + dependencies: + frac "~1.1.2" + +ssri@^10.0.0: + version "10.0.6" + resolved "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz" + 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" + integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +standard-as-callback@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz" + integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== + +static-eval@2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz" + integrity sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg== + dependencies: + escodegen "^1.8.1" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +string_decoder@^1.1.1, string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-template@~0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz" + integrity sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw== + +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^1.0.1, "string-width@^1.0.2 || 2 || 3 || 4": + version "1.0.2" + resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz" + integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^5.0.1: + version "5.1.2" + resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" + integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^2.0.0, strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== + +strip-json-comments@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +table@^6.0.4: + version "6.8.2" + resolved "https://registry.npmjs.org/table/-/table-6.8.2.tgz" + integrity sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA== + dependencies: + ajv "^8.0.1" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + +tar-fs@^1.13.0: + version "1.16.3" + resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz" + integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw== + dependencies: + chownr "^1.0.1" + mkdirp "^0.5.1" + pump "^1.0.0" + tar-stream "^1.1.2" + +tar-stream@^1.1.2: + version "1.6.2" + resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz" + integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== + dependencies: + bl "^1.0.0" + buffer-alloc "^1.2.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.3.0" + to-buffer "^1.1.1" + xtend "^4.0.0" + +tar-stream@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + 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" + +tar@^6.1.11, tar@^6.1.2: + version "6.2.1" + resolved "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^5.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + +tdigest@^0.1.1: + version "0.1.2" + resolved "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz" + 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" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-hex@1.0.x: + version "1.0.0" + resolved "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +thriftrw@^3.5.0: + version "3.11.4" + resolved "https://registry.npmjs.org/thriftrw/-/thriftrw-3.11.4.tgz" + integrity sha512-UcuBd3eanB3T10nXWRRMwfwoaC6VMk7qe3/5YIWP2Jtw+EbHqJ0p1/K3x8ixiR5dozKSSfcg1W+0e33G1Di3XA== + dependencies: + bufrw "^1.2.1" + error "7.0.2" + long "^2.4.0" + +tiny-case@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz" + integrity sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q== + +tmp@^0.2.0: + version "0.2.3" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz" + integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-buffer@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz" + integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +toposort@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz" + integrity sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg== + +"traverse@>=0.3.0 <0.4": + version "0.3.9" + resolved "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz" + integrity sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ== + +tree-kill@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + +triple-beam@^1.3.0: + version "1.4.1" + resolved "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz" + integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== + +ts-node-dev@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz" + integrity sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w== + dependencies: + chokidar "^3.5.1" + dynamic-dedupe "^0.3.0" + minimist "^1.2.6" + mkdirp "^1.0.4" + resolve "^1.0.0" + rimraf "^2.6.1" + source-map-support "^0.5.12" + tree-kill "^1.2.2" + ts-node "^10.4.0" + tsconfig "^7.0.0" + +ts-node@^10.4.0, ts-node@>=9.0.0: + version "10.9.2" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tsconfig@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz" + integrity sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw== + dependencies: + "@types/strip-bom" "^3.0.0" + "@types/strip-json-comments" "0.0.30" + strip-bom "^3.0.0" + strip-json-comments "^2.0.0" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz" + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== + dependencies: + safe-buffer "^5.0.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" + integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== + dependencies: + prelude-ls "~1.1.2" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" + 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" + integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript@*, typescript@>=2.7, typescript@5.4.2: + version "5.4.2" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz" + integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ== + +underscore@1.12.1: + version "1.12.1" + resolved "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz" + integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw== + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +unique-filename@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz" + integrity sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g== + dependencies: + unique-slug "^4.0.0" + +unique-slug@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz" + integrity sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ== + dependencies: + imurmurhash "^0.1.4" + +unpipe@~1.0.0, unpipe@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +unzipper@^0.10.11: + version "0.10.14" + resolved "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz" + integrity sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g== + dependencies: + big-integer "^1.6.17" + binary "~0.3.0" + bluebird "~3.4.1" + buffer-indexof-polyfill "~1.0.0" + duplexer2 "~0.1.4" + fstream "^1.0.12" + graceful-fs "^4.2.2" + listenercount "~1.0.1" + readable-stream "~2.3.6" + setimmediate "~1.0.4" + +update-browserslist-db@^1.0.13: + version "1.0.16" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz" + integrity sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ== + dependencies: + escalade "^3.1.2" + picocolors "^1.0.1" + +uri-js@^4.2.2, uri-js@^4.4.1: + version "4.4.1" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +uuid@^3.0.0: + version "3.4.0" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +uuid@^8.3.0: + version "8.3.2" + resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +uuid@9.0.1: + version "9.0.1" + resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +v8-compile-cache@^2.0.3: + version "2.4.0" + resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz" + integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw== + +v8-to-istanbul@^9.0.1: + version "9.2.0" + resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz" + integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +which-pm-runs@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz" + integrity sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA== + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +which@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/which/-/which-4.0.0.tgz" + integrity sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg== + dependencies: + isexe "^3.1.1" + +wide-align@^1.1.0: + version "1.1.5" + resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== + dependencies: + string-width "^1.0.2 || 2 || 3 || 4" + +winston-transport@^4.7.0: + version "4.7.0" + resolved "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz" + integrity sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg== + dependencies: + logform "^2.3.2" + readable-stream "^3.6.0" + triple-beam "^1.3.0" + +winston@3.12.0: + version "3.12.0" + resolved "https://registry.npmjs.org/winston/-/winston-3.12.0.tgz" + integrity sha512-OwbxKaOlESDi01mC9rkM0dQqQt2I8DAUMRLZ/HpbwvDXm85IryEHgoogy5fziQy38PntgZsLlhAYHz//UPHZ5w== + dependencies: + "@colors/colors" "^1.6.0" + "@dabh/diagnostics" "^2.0.2" + async "^3.2.3" + is-stream "^2.0.0" + logform "^2.4.0" + one-time "^1.0.0" + readable-stream "^3.4.0" + safe-stable-stringify "^2.3.1" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.7.0" + +wmf@~1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz" + integrity sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw== + +word-wrap@^1.2.5, word-wrap@~1.2.3: + version "1.2.5" + resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +word@~0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/word/-/word-0.3.0.tgz" + integrity sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA== + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +xlsx-populate@1.21.0: + version "1.21.0" + resolved "https://registry.npmjs.org/xlsx-populate/-/xlsx-populate-1.21.0.tgz" + integrity sha512-8v2Gm8BehXo6LU7KT802QoXTPkYY1SKk5V8g/UuYZnNB3JzXqud/P99Pxr2yXeKyt+sKlCatmidz6jQNie1hRw== + dependencies: + cfb "^1.1.3" + jszip "^3.2.2" + lodash "^4.17.15" + sax "^1.2.4" + +xlsx@*, xlsx@0.18.5: + version "0.18.5" + resolved "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz" + integrity sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ== + dependencies: + adler-32 "~1.3.0" + cfb "~1.2.1" + codepage "~1.15.0" + crc-32 "~1.2.1" + ssf "~0.11.2" + wmf "~1.0.1" + word "~0.3.0" + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" + 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" + 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" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.3.1: + version "17.7.2" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +yup@1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/yup/-/yup-1.4.0.tgz" + integrity sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg== + dependencies: + property-expr "^2.0.5" + tiny-case "^1.0.3" + toposort "^2.0.2" + type-fest "^2.19.0" + +zip-stream@^4.1.0: + version "4.1.1" + resolved "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz" + integrity sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ== + dependencies: + archiver-utils "^3.0.4" + compress-commons "^4.1.2" + readable-stream "^3.6.0" diff --git a/health-services/project/CHANGELOG.md b/health-services/project/CHANGELOG.md index a27826b5875..95369041416 100644 --- a/health-services/project/CHANGELOG.md +++ b/health-services/project/CHANGELOG.md @@ -1,5 +1,34 @@ All notable changes to this module will be documented in this file. +## 1.1.5 - 2024-08-07 +- Added UserAction functionality with support for Location capture. + +## 1.1.4 - 2024-05-29 +- Integrated Core 2.9LTS +- Integrated Boundary v2 functionality +- Upgraded to health models 1.0.20 and health common 1.0.16 +- Boundary v2 Integration +- MDMS v2 integration +- Beneficiary Tag null check in update +- 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. +- Added numberOfSessions field in additional details for attendance registry. + +## 1.1.1 - 2023-11-15 +- Added tag in project beneficiary + +## 1.1.1-beta 19-10-2023 + - Added support for multi round, Added new validator for project task. + +## 1.1.0 + - models library version update + ## 1.0.0 + - Base version + -- Base version \ No newline at end of file diff --git a/health-services/project/README.md b/health-services/project/README.md index 518e8b8653a..2c12f3b8091 100644 --- a/health-services/project/README.md +++ b/health-services/project/README.md @@ -130,7 +130,6 @@ Project service APIs - contains create, update, delete and search end point - update-project-resource-bulk-topic - delete-project-resource-bulk-topic - ### Kafka Producers - save-project-staff-topic @@ -153,7 +152,20 @@ Project service APIs - contains create, update, delete and search end point - update-project-resource-topic - delete-project-resource-topic - ## Pre commit script [commit-msg](https://gist.github.com/jayantp-egov/14f55deb344f1648503c6be7e580fa12) + +## Updates +- Project Staff Search + - `staffId`, and `projectId` now accepts a list of entities instead of single entity to search project staff +- Project Task Search + - `projectId`, `projectBeneficiaryId`, and `projectBeneficiaryClientReferenceId` now accepts list of entities instead of single entity to search project task +- Project Beneficiary Search + - `projectId`, and `beneficiaryId` now accepts a list of entities instead of single entity to search project beneficiary +- Project Resource Search + - `projectId` now accepts a list of entities instead of single entity to search project resources +## Usage +- Start the service +- Access the API endpoints for searching various project entities +- Pass list parameters for the search fields mentioned in updates \ No newline at end of file diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index f0a5c1e5e4b..fd0b688dcc3 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -5,16 +5,17 @@ project jar project - 1.0.1 + 1.1.5 - 1.8 + 17 ${java.version} ${java.version} + 1.18.22 org.springframework.boot spring-boot-starter-parent - 2.2.6.RELEASE + 3.2.2 src/main/java @@ -44,12 +45,12 @@ org.egov.common health-services-common - 1.0.8-SNAPSHOT + 1.0.18-SNAPSHOT org.egov.common health-services-models - 1.0.0-SNAPSHOT + 1.0.21-SNAPSHOT compile @@ -69,42 +70,49 @@ org.flywaydb flyway-core + 9.22.3 org.postgresql postgresql - 42.2.2.jre7 + 42.7.1 + + + org.egov.services + tracer + 2.9.0-SNAPSHOT org.springframework.boot spring-boot-starter-test test - + + junit + junit + 4.13.2 + test + io.swagger swagger-core 1.5.18 - - - org.egov.services - digit-models - 1.0.0-SNAPSHOT - org.projectlombok lombok + ${lombok.version} true com.fasterxml.jackson.datatype jackson-datatype-jsr310 - - javax.validation - validation-api + commons-io + commons-io + 2.13.0 + test diff --git a/health-services/project/src/main/java/org/egov/project/Constants.java b/health-services/project/src/main/java/org/egov/project/Constants.java index fdf557ad07b..66333c64989 100644 --- a/health-services/project/src/main/java/org/egov/project/Constants.java +++ b/health-services/project/src/main/java/org/egov/project/Constants.java @@ -53,4 +53,15 @@ public interface Constants { String PIPE = "||"; String PROJECT_ID = "projectId"; + + String TASK_QUANTITY = "taskQuantity"; + + String HOUSEHOLD_ID = "HouseholdId"; + + String SET_USER_ACTION = "setUserActions"; + + String GET_USER_ACTION = "getUserActions"; + + String PROJECT_USER_ACTION_ENRICHMENT_ERROR = "PROJECT_USER_ACTION_ENRICHMENT_ERROR"; + } diff --git a/health-services/project/src/main/java/org/egov/project/config/MainConfiguration.java b/health-services/project/src/main/java/org/egov/project/config/MainConfiguration.java index 216b4abcd54..b9bad965c70 100644 --- a/health-services/project/src/main/java/org/egov/project/config/MainConfiguration.java +++ b/health-services/project/src/main/java/org/egov/project/config/MainConfiguration.java @@ -22,7 +22,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.util.TimeZone; @Import({TracerConfiguration.class}) @Configuration diff --git a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java index a055d380ddb..26759e381e2 100644 --- a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java +++ b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java @@ -1,5 +1,7 @@ package org.egov.project.config; +import java.util.List; + import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -177,6 +179,47 @@ public class ProjectConfiguration { @Value("${project.mdms.module}") private String mdmsModule; + @Value("${task.mdms.module}") + private String taskMdmsModule; + @Value("${egov.location.hierarchy.type}") private String locationHierarchyType; + + @Value("${egov.user.id.validator}") + private String egovUserIdValidator; + + @Value("${project.staff.attendance.topic}") + private String projectStaffAttendanceTopic; + + @Value("${project.management.system.kafka.update.date.topic}") + private String updateProjectDateTopic; + + + // closed household task + @Value("${project.user.action.kafka.create.topic}") + private String createUserActionTopic; + + @Value("${project.user.action.consumer.bulk.create.topic}") + private String bulkCreateUserActionTopic; + + @Value("${project.user.action.kafka.update.topic}") + private String updateUserActionTopic; + + @Value("${project.user.action.consumer.bulk.update.topic}") + private String bulkUpdateUserActionTopic; + + @Value("${project.location.capture.consumer.bulk.create.topic}") + private String bulkCreateLocationCaptureTopic; + + @Value("${project.location.capture.kafka.create.topic}") + private String createLocationCaptureTopic; + + @Value("${egov.boundary.host}") + private String boundaryServiceHost; + + @Value("${egov.boundary.search.url}") + private String boundarySearchUrl; + + @Value("${project.task.no.resource.validation.status}") + private List noResourceStatuses; } diff --git a/health-services/project/src/main/java/org/egov/project/consumer/ProjectBeneficiaryConsumer.java b/health-services/project/src/main/java/org/egov/project/consumer/ProjectBeneficiaryConsumer.java index 2cc3309aedc..fcf11150c4e 100644 --- a/health-services/project/src/main/java/org/egov/project/consumer/ProjectBeneficiaryConsumer.java +++ b/health-services/project/src/main/java/org/egov/project/consumer/ProjectBeneficiaryConsumer.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.project.BeneficiaryBulkRequest; import org.egov.common.models.project.ProjectBeneficiary; import org.egov.project.service.ProjectBeneficiaryService; @@ -38,7 +39,7 @@ public List bulkCreate(Map consumerRecord, BeneficiaryBulkRequest request = objectMapper.convertValue(consumerRecord, BeneficiaryBulkRequest.class); return projectBeneficiaryService.create(request, true); } catch (Exception exception) { - log.error("error in project beneficiary consumer bulk create", exception); + log.error("error in project beneficiary consumer bulk create", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -50,7 +51,7 @@ public List bulkUpdate(Map consumerRecord, BeneficiaryBulkRequest request = objectMapper.convertValue(consumerRecord, BeneficiaryBulkRequest.class); return projectBeneficiaryService.update(request, true); } catch (Exception exception) { - log.error("error in project beneficiary consumer bulk update", exception); + log.error("error in project beneficiary consumer bulk update", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -62,7 +63,7 @@ public List bulkDelete(Map consumerRecord, BeneficiaryBulkRequest request = objectMapper.convertValue(consumerRecord, BeneficiaryBulkRequest.class); return projectBeneficiaryService.delete(request, true); } catch (Exception exception) { - log.error("error in project beneficiary consumer bulk delete", exception); + log.error("error in project beneficiary consumer bulk delete", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/project/src/main/java/org/egov/project/consumer/ProjectFacilityConsumer.java b/health-services/project/src/main/java/org/egov/project/consumer/ProjectFacilityConsumer.java index 2525e68bfbe..25049dda375 100644 --- a/health-services/project/src/main/java/org/egov/project/consumer/ProjectFacilityConsumer.java +++ b/health-services/project/src/main/java/org/egov/project/consumer/ProjectFacilityConsumer.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.project.ProjectFacility; import org.egov.common.models.project.ProjectFacilityBulkRequest; import org.egov.project.service.ProjectFacilityService; @@ -34,7 +35,7 @@ public List bulkCreate(Map consumerRecord, ProjectFacilityBulkRequest request = objectMapper.convertValue(consumerRecord, ProjectFacilityBulkRequest.class); return service.create(request, true); } catch (Exception exception) { - log.error("error in project facility consumer bulk create", exception); + log.error("error in project facility consumer bulk create", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -46,7 +47,7 @@ public List bulkUpdate(Map consumerRecord, ProjectFacilityBulkRequest request = objectMapper.convertValue(consumerRecord, ProjectFacilityBulkRequest.class); return service.update(request, true); } catch (Exception exception) { - log.error("error in project facility consumer bulk update", exception); + log.error("error in project facility consumer bulk update", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -58,7 +59,7 @@ public List bulkDelete(Map consumerRecord, ProjectFacilityBulkRequest request = objectMapper.convertValue(consumerRecord, ProjectFacilityBulkRequest.class); return service.delete(request, true); } catch (Exception exception) { - log.error("error in project facility consumer bulk delete", exception); + log.error("error in project facility consumer bulk delete", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/project/src/main/java/org/egov/project/consumer/ProjectResourceConsumer.java b/health-services/project/src/main/java/org/egov/project/consumer/ProjectResourceConsumer.java index d3ffa6100d6..d3801b3bec9 100644 --- a/health-services/project/src/main/java/org/egov/project/consumer/ProjectResourceConsumer.java +++ b/health-services/project/src/main/java/org/egov/project/consumer/ProjectResourceConsumer.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.project.ProjectResource; import org.egov.common.models.project.ProjectResourceBulkRequest; import org.egov.project.service.ProjectResourceService; @@ -35,7 +36,7 @@ public List bulkCreate(Map consumerRecord, ProjectResourceBulkRequest request = objectMapper.convertValue(consumerRecord, ProjectResourceBulkRequest.class); return service.create(request, true); } catch (Exception exception) { - log.error("error in project resource consumer bulk create", exception); + log.error("error in project resource consumer bulk create", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -47,7 +48,7 @@ public List bulkUpdate(Map consumerRecord, ProjectResourceBulkRequest request = objectMapper.convertValue(consumerRecord, ProjectResourceBulkRequest.class); return service.update(request, true); } catch (Exception exception) { - log.error("error in project resource consumer bulk update", exception); + log.error("error in project resource consumer bulk update", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -59,7 +60,7 @@ public List bulkDelete(Map consumerRecord, ProjectResourceBulkRequest request = objectMapper.convertValue(consumerRecord, ProjectResourceBulkRequest.class); return service.delete(request, true); } catch (Exception exception) { - log.error("error in project resource consumer bulk delete", exception); + log.error("error in project resource consumer bulk delete", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/project/src/main/java/org/egov/project/consumer/ProjectStaffConsumer.java b/health-services/project/src/main/java/org/egov/project/consumer/ProjectStaffConsumer.java index 168e8665cf1..21e50fbba89 100644 --- a/health-services/project/src/main/java/org/egov/project/consumer/ProjectStaffConsumer.java +++ b/health-services/project/src/main/java/org/egov/project/consumer/ProjectStaffConsumer.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.project.ProjectStaff; import org.egov.common.models.project.ProjectStaffBulkRequest; import org.egov.project.service.ProjectStaffService; @@ -34,7 +35,7 @@ public List bulkCreate(Map consumerRecord, ProjectStaffBulkRequest request = objectMapper.convertValue(consumerRecord, ProjectStaffBulkRequest.class); return service.create(request, true); } catch (Exception exception) { - log.error("error in project staff consumer bulk create", exception); + log.error("error in project staff consumer bulk create", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -46,7 +47,7 @@ public List bulkUpdate(Map consumerRecord, ProjectStaffBulkRequest request = objectMapper.convertValue(consumerRecord, ProjectStaffBulkRequest.class); return service.update(request, true); } catch (Exception exception) { - log.error("error in project staff consumer bulk update", exception); + log.error("error in project staff consumer bulk update", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -58,7 +59,7 @@ public List bulkDelete(Map consumerRecord, ProjectStaffBulkRequest request = objectMapper.convertValue(consumerRecord, ProjectStaffBulkRequest.class); return service.delete(request, true); } catch (Exception exception) { - log.error("error in project staff consumer bulk delete", exception); + log.error("error in project staff consumer bulk delete", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/project/src/main/java/org/egov/project/consumer/ProjectTaskConsumer.java b/health-services/project/src/main/java/org/egov/project/consumer/ProjectTaskConsumer.java index 21d56dd266b..aa2c9155cdb 100644 --- a/health-services/project/src/main/java/org/egov/project/consumer/ProjectTaskConsumer.java +++ b/health-services/project/src/main/java/org/egov/project/consumer/ProjectTaskConsumer.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskBulkRequest; import org.egov.project.service.ProjectTaskService; @@ -38,7 +39,7 @@ public List bulkCreate(Map consumerRecord, TaskBulkRequest request = objectMapper.convertValue(consumerRecord, TaskBulkRequest.class); return projectTaskService.create(request, true); } catch (Exception exception) { - log.error("error in project task consumer bulk create", exception); + log.error("error in project task consumer bulk create", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -50,7 +51,7 @@ public List bulkUpdate(Map consumerRecord, TaskBulkRequest request = objectMapper.convertValue(consumerRecord, TaskBulkRequest.class); return projectTaskService.update(request, true); } catch (Exception exception) { - log.error("error in project task consumer bulk update", exception); + log.error("error in project task consumer bulk update", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -62,7 +63,7 @@ public List bulkDelete(Map consumerRecord, TaskBulkRequest request = objectMapper.convertValue(consumerRecord, TaskBulkRequest.class); return projectTaskService.delete(request, true); } catch (Exception exception) { - log.error("error in project task consumer bulk delete", exception); + log.error("error in project task consumer bulk delete", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/project/src/main/java/org/egov/project/consumer/UserActionConsumer.java b/health-services/project/src/main/java/org/egov/project/consumer/UserActionConsumer.java new file mode 100644 index 00000000000..f01d2e00913 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/consumer/UserActionConsumer.java @@ -0,0 +1,103 @@ +package org.egov.project.consumer; + +import java.util.Map; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.project.service.LocationCaptureService; +import org.egov.project.service.UserActionService; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class UserActionConsumer { + + private final UserActionService userActionService; + private final LocationCaptureService locationCaptureService; + private final ObjectMapper objectMapper; + + @Autowired + public UserActionConsumer(UserActionService userActionService, LocationCaptureService locationCaptureService, ObjectMapper objectMapper) { + // Constructor injection for services and object mapper + this.userActionService = userActionService; + this.locationCaptureService = locationCaptureService; + this.objectMapper = objectMapper; + } + + /** + * Kafka listener for bulk creating user actions. + * + * @param consumerRecord The Kafka consumer record as a map. + * @param topic The topic from which the message was received. + * @return List of created UserAction objects. + */ + @KafkaListener(topics = "${project.user.action.consumer.bulk.create.topic}") + public void bulkCreateUserAction(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + // Convert consumer record to UserActionBulkRequest object + UserActionBulkRequest request = objectMapper.convertValue(consumerRecord, UserActionBulkRequest.class); + // Call the userActionService to handle the create operation + userActionService.create(request, true); + } catch (Exception exception) { + // Log any exception that occurs + log.error("Error processing bulk create for user actions from topic {}: {}", topic, ExceptionUtils.getStackTrace(exception)); + // throw custom exception + throw new CustomException("PROJECT_USER_ACTION_BULK_CREATE", exception.getMessage()); + } + } + + /** + * Kafka listener for bulk updating user actions. + * + * @param consumerRecord The Kafka consumer record as a map. + * @param topic The topic from which the message was received. + * @return List of updated UserAction objects. + */ + @KafkaListener(topics = "${project.user.action.consumer.bulk.update.topic}") + public void bulkUpdateUserAction(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + // Convert consumer record to UserActionBulkRequest object + UserActionBulkRequest request = objectMapper.convertValue(consumerRecord, UserActionBulkRequest.class); + // Call the userActionService to handle the update operation + userActionService.update(request, true); + } catch (Exception exception) { + // Log any exception that occurs + log.error("Error processing bulk update for user actions from topic {}: {}", topic, ExceptionUtils.getStackTrace(exception)); + // throw custom exception + throw new CustomException("PROJECT_USER_ACTION_BULK_UPDATE", exception.getMessage()); + } + } + + /** + * Kafka listener for bulk creating location captures. + * + * @param consumerRecord The Kafka consumer record as a map. + * @param topic The topic from which the message was received. + * @return List of created UserAction objects. + */ + @KafkaListener(topics = "${project.location.capture.consumer.bulk.create.topic}") + public void bulkCreateLocationCapture(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + // Convert consumer record to UserActionBulkRequest object + UserActionBulkRequest request = objectMapper.convertValue(consumerRecord, UserActionBulkRequest.class); + // Call the locationCaptureService to handle the create operation + locationCaptureService.create(request, true); + } catch (Exception exception) { + // Log any exception that occurs + log.error("Error processing bulk create for location captures from topic {}: {}", topic, ExceptionUtils.getStackTrace(exception)); + // throw custom exception + throw new CustomException("PROJECT_USER_ACTION_LOCATION_CAPTURE_BULK_CREATE", exception.getMessage()); + } + } + +} diff --git a/health-services/project/src/main/java/org/egov/project/repository/LocationCaptureRepository.java b/health-services/project/src/main/java/org/egov/project/repository/LocationCaptureRepository.java new file mode 100644 index 00000000000..9127c0272b8 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/repository/LocationCaptureRepository.java @@ -0,0 +1,135 @@ +package org.egov.project.repository; + +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.builder.GenericQueryBuilder; +import org.egov.common.data.query.builder.QueryFieldChecker; +import org.egov.common.data.query.builder.SelectQueryBuilder; +import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionSearch; +import org.egov.common.producer.Producer; +import org.egov.common.utils.CommonUtils; +import org.egov.project.repository.rowmapper.LocationCaptureRowMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdMethod; + +@Repository +@Slf4j +public class LocationCaptureRepository extends GenericRepository { + + private final String selectQuery = "SELECT id, clientreferenceid, tenantid, projectid, latitude, longitude, locationaccuracy, boundarycode, action, createdby, createdtime, lastmodifiedby, lastmodifiedtime, clientcreatedtime, clientlastmodifiedtime, clientcreatedby, clientlastmodifiedby, additionaldetails FROM user_location ul "; + + @Autowired + protected LocationCaptureRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, LocationCaptureRowMapper locationCaptureRowMapper) { + // Initialize the repository with producer, JDBC template, Redis template, query builder, and row mapper + super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, locationCaptureRowMapper, Optional.of("user_location")); + } + + /** + * Finds user locations based on search criteria and URL parameters. + * + * @param searchObject The search criteria for user locations. + * @param urlParams The URL parameters including pagination and filtering information. + * @return A SearchResponse containing the list of user locations and the total count. + */ + public SearchResponse find(UserActionSearch searchObject, URLParams urlParams) { + log.info("Executing find with searchObject: {} and urlParams: {}", searchObject, urlParams); + + String query = selectQuery + ""; + + Map paramsMap = new HashMap<>(); + List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); + query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); + query = query.replace("id IN (:id)", "ul.id IN (:id)"); + query = query.replace("clientReferenceId IN (:clientReferenceId)", "ul.clientReferenceId IN (:clientReferenceId)"); + + if (CollectionUtils.isEmpty(whereFields)) { + query = query + " WHERE ul.tenantId=:tenantId "; + } else { + query = query + " AND ul.tenantId=:tenantId "; + } + + if (urlParams.getLastChangedSince() != null) { + query = query + " AND ul.lastModifiedTime>=:lastModifiedTime "; + } + paramsMap.put("tenantId", urlParams.getTenantId()); + paramsMap.put("lastModifiedTime", urlParams.getLastChangedSince()); + + try { + log.debug("Executing query to fetch total count"); + Long totalCount = CommonUtils.constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + + query = query + " ORDER BY ul.id ASC LIMIT :limit OFFSET :offset"; + paramsMap.put("limit", urlParams.getLimit()); + paramsMap.put("offset", urlParams.getOffset()); + + log.debug("Executing query to fetch user locations: {}", query); + List locationCaptureList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + + log.info("Successfully fetched user locations: {}", locationCaptureList.size()); + return SearchResponse.builder().response(locationCaptureList).totalCount(totalCount).build(); + } catch (Exception e) { + log.error("Failed to execute query for finding user locations", e); + return SearchResponse.builder().response(Collections.emptyList()).totalCount(0L).build(); + } + } + + /** + * Finds user locations by their IDs, first checking the cache before querying the database. + * + * @param ids The list of IDs to search for. + * @param columnName The name of the column to search by. + * @return A SearchResponse containing the list of user locations found. + */ + public SearchResponse findById(List ids, String columnName) { + log.info("Executing findById with ids: {} and columnName: {}", ids, columnName); + + List objFound = findInCache(ids); + + if (!objFound.isEmpty()) { + Method idMethod = getIdMethod(objFound, columnName); + ids.removeAll(objFound.stream() + .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) + .collect(Collectors.toList())); + + if (ids.isEmpty()) { + log.info("All requested user locations found in cache"); + return SearchResponse.builder().response(objFound).build(); + } + } + + String query = String.format(selectQuery + " WHERE ul.%s IN (:ids)", columnName); + Map paramMap = new HashMap<>(); + paramMap.put("ids", ids); + + try { + log.debug("Executing query to fetch user locations by ID: {}", query); + List locationCaptureList = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + + objFound.addAll(locationCaptureList); + putInCache(objFound); + + log.info("Successfully fetched user locations by ID: {}", locationCaptureList.size()); + return SearchResponse.builder().response(objFound).build(); + } catch (Exception e) { + log.error("Failed to execute query for finding user locations by ID", e); + return SearchResponse.builder().response(Collections.emptyList()).totalCount(0L).build(); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/repository/ProjectBeneficiaryRepository.java b/health-services/project/src/main/java/org/egov/project/repository/ProjectBeneficiaryRepository.java index df29b9869c0..56d23bca00a 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/ProjectBeneficiaryRepository.java +++ b/health-services/project/src/main/java/org/egov/project/repository/ProjectBeneficiaryRepository.java @@ -1,17 +1,32 @@ package org.egov.project.repository; import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.builder.GenericQueryBuilder; +import org.egov.common.data.query.builder.QueryFieldChecker; import org.egov.common.data.query.builder.SelectQueryBuilder; +import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.household.HouseholdMember; import org.egov.common.models.project.ProjectBeneficiary; import org.egov.common.producer.Producer; import org.egov.project.repository.rowmapper.ProjectBeneficiaryRowMapper; +import org.egov.common.models.project.ProjectBeneficiarySearch; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; +import org.springframework.util.ReflectionUtils; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; +import static org.egov.common.utils.CommonUtils.getIdMethod; @Repository @Slf4j @@ -24,5 +39,84 @@ public ProjectBeneficiaryRepository(Producer producer, NamedParameterJdbcTemplat super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, projectBeneficiaryRowMapper, Optional.of("project_beneficiary")); } + + public SearchResponse find(ProjectBeneficiarySearch householdMemberSearch, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) { + + Map paramsMap = new HashMap<>(); + StringBuilder queryBuilder = new StringBuilder(); + + String query = "SELECT * FROM project_beneficiary "; + + List whereFields = GenericQueryBuilder.getFieldsWithCondition(householdMemberSearch, QueryFieldChecker.isNotNull, paramsMap); + query = GenericQueryBuilder.generateQuery(query, whereFields).toString().trim(); + + query = query + " AND tenantId=:tenantId "; + + if (query.contains(this.tableName + " AND")) { + query = query.replace(this.tableName + " AND", this.tableName + " WHERE"); + } + + queryBuilder.append(query); + + if (Boolean.FALSE.equals(includeDeleted)) { + queryBuilder.append("AND isDeleted=:isDeleted "); + } + + if (lastChangedSince != null) { + queryBuilder.append("AND lastModifiedTime>=:lastModifiedTime "); + } + + paramsMap.put("tenantId", tenantId); + paramsMap.put("isDeleted", includeDeleted); + paramsMap.put("lastModifiedTime", lastChangedSince); + + queryBuilder.append(" ORDER BY id ASC "); + + Long totalCount = constructTotalCountCTEAndReturnResult(queryBuilder.toString(), paramsMap, this.namedParameterJdbcTemplate); + + queryBuilder.append(" LIMIT :limit OFFSET :offset"); + paramsMap.put("limit", limit); + paramsMap.put("offset", offset); + + List projectBeneficiaries = this.namedParameterJdbcTemplate.query(queryBuilder.toString(), paramsMap, this.rowMapper); + + return SearchResponse.builder().totalCount(totalCount).response(projectBeneficiaries).build(); + } + + public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { + List objFound = findInCache(ids); + if (!includeDeleted) { + objFound = objFound.stream() + .filter(entity -> entity.getIsDeleted().equals(false)) + .collect(Collectors.toList()); + } + if (!objFound.isEmpty()) { + Method idMethod = getIdMethod(objFound, columnName); + ids.removeAll(objFound.stream() + .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) + .collect(Collectors.toList())); + if (ids.isEmpty()) { + log.info("all objects were found in the cache, returning objects"); + return SearchResponse.builder().response(objFound).build(); + } + } + + String query = String.format("SELECT * FROM project_beneficiary where %s IN (:ids) AND isDeleted = false", columnName); + if (null != includeDeleted && includeDeleted) { + query = String.format("SELECT * FROM project_beneficiary WHERE %s IN (:ids)", columnName); + } + Map paramMap = new HashMap(); + paramMap.put("ids", ids); + + objFound.addAll(this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper)); + putInCache(objFound); + log.info("returning objects from the database"); + return SearchResponse.builder().response(objFound).build(); + } } diff --git a/health-services/project/src/main/java/org/egov/project/repository/ProjectRepository.java b/health-services/project/src/main/java/org/egov/project/repository/ProjectRepository.java index fd1d029bb4e..ae7b4c9994b 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/ProjectRepository.java +++ b/health-services/project/src/main/java/org/egov/project/repository/ProjectRepository.java @@ -1,12 +1,16 @@ package org.egov.project.repository; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.ProjectSearchURLParams; import org.egov.common.models.project.Document; import org.egov.common.models.project.Project; import org.egov.common.models.project.ProjectRequest; +import org.egov.common.models.project.ProjectSearch; import org.egov.common.models.project.Target; import org.egov.common.producer.Producer; import org.egov.project.repository.querybuilder.DocumentQueryBuilder; @@ -101,6 +105,51 @@ public List getProjects(ProjectRequest project, Integer limit, Integer return buildProjectSearchResult(projects, targets, documents, ancestors, descendants); } + public List getProjects(@NotNull @Valid ProjectSearch projectSearch, @Valid ProjectSearchURLParams urlParams) { + + //Fetch Projects based on search criteria + List projects = getProjectsBasedOnV2SearchCriteria(projectSearch, urlParams); + + Set projectIds = projects.stream().map(Project :: getId).collect(Collectors.toSet()); + + List ancestors = null; + List descendants = null; + //Get Project ancestors if includeAncestors flag is true + if (urlParams.getIncludeAncestors()) { + ancestors = getProjectAncestors(projects); + if (ancestors != null && !ancestors.isEmpty()) { + List ancestorProjectIds = ancestors.stream().map(Project :: getId).collect(Collectors.toList()); + projectIds.addAll(ancestorProjectIds); + } + } + //Get Project descendants if includeDescendants flag is true + if (urlParams.getIncludeDescendants()) { + descendants = getProjectDescendants(projects); + if (descendants != null && !descendants.isEmpty()) { + List descendantsProjectIds = descendants.stream().map(Project :: getId).collect(Collectors.toList()); + projectIds.addAll(descendantsProjectIds); + } + } + + //Fetch targets based on Project Ids + List targets = getTargetsBasedOnProjectIds(projectIds); + + //Fetch documents based on Project Ids + List documents = getDocumentsBasedOnProjectIds(projectIds); + + //Construct Project Objects with fetched projects, targets and documents using Project id + return buildProjectSearchResult(projects, targets, documents, ancestors, descendants); + } + + private List getProjectsBasedOnV2SearchCriteria(@NotNull @Valid ProjectSearch projectSearch, ProjectSearchURLParams urlParams) { + List preparedStmtList = new ArrayList<>(); + String query = queryBuilder.getProjectSearchQuery(projectSearch, urlParams, preparedStmtList, Boolean.FALSE); + List projects = jdbcTemplate.query(query, addressRowMapper, preparedStmtList.toArray()); + + log.info("Fetched project list based on given search criteria"); + return projects; + } + /* Fetch Projects based on search criteria */ private List getProjectsBasedOnSearchCriteria(List projectsRequest, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted, Long createdFrom, Long createdTo) { List preparedStmtList = new ArrayList<>(); @@ -112,7 +161,7 @@ private List getProjectsBasedOnSearchCriteria(List projectsReq } /* Fetch Projects based on Project ids */ - private List getProjectsBasedOnProjectIds(List projectIds, List preparedStmtList) { + public List getProjectsBasedOnProjectIds(List projectIds, List preparedStmtList) { String query = queryBuilder.getProjectSearchQueryBasedOnIds(projectIds, preparedStmtList); List projects = jdbcTemplate.query(query, addressRowMapper, preparedStmtList.toArray()); log.info("Fetched project list based on given Project Ids"); @@ -301,4 +350,21 @@ public Integer getProjectCount(ProjectRequest project, String tenantId, Long las log.info("Total project count is : " + count); return count; } + + /** + * Get the count of projects based on the given search criteria (using dynamic + * query build at the run time) + * @return + */ + public Integer getProjectCount(ProjectSearch projectSearch, ProjectSearchURLParams urlParams) { + List preparedStatement = new ArrayList<>(); + String query = queryBuilder.getSearchCountQueryString(projectSearch, urlParams, preparedStatement); + + if (query == null) + return 0; + + Integer count = jdbcTemplate.queryForObject(query, preparedStatement.toArray(), Integer.class); + log.info("Total project count is : " + count); + return count; + } } \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java b/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java index 0da3ea81713..3f5895633d3 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java +++ b/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java @@ -1,31 +1,34 @@ package org.egov.project.repository; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.egov.common.data.query.builder.GenericQueryBuilder; import org.egov.common.data.query.builder.QueryFieldChecker; import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskResource; import org.egov.common.models.project.TaskSearch; import org.egov.common.producer.Producer; +import org.egov.common.utils.CommonUtils; import org.egov.project.repository.rowmapper.ProjectTaskRowMapper; import org.egov.project.repository.rowmapper.TaskResourceRowMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.getIdList; import static org.egov.common.utils.CommonUtils.getIdMethod; @@ -43,9 +46,9 @@ protected ProjectTaskRepository(Producer producer, NamedParameterJdbcTemplate na super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, rowMapper, Optional.of("project_task")); } - public List find(TaskSearch searchObject, Integer limit, Integer offset, String tenantId, + public SearchResponse find(TaskSearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { - String query = "SELECT * FROM project_task pt LEFT JOIN address a ON pt.addressid = a.id"; + String query = "SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM project_task pt LEFT JOIN address a ON pt.addressid = a.id"; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); @@ -53,7 +56,11 @@ public List find(TaskSearch searchObject, Integer limit, Integer offset, S query = query.replace("id IN (:id)", "pt.id IN (:id)"); query = query.replace("clientReferenceId IN (:clientReferenceId)", "pt.clientReferenceId IN (:clientReferenceId)"); - query = query + " and pt.tenantId=:tenantId "; + if(CollectionUtils.isEmpty(whereFields)) { + query = query + " where pt.tenantId=:tenantId "; + } else { + query = query + " and pt.tenantId=:tenantId "; + } if (Boolean.FALSE.equals(includeDeleted)) { query = query + "and isDeleted=:isDeleted "; } @@ -61,15 +68,20 @@ public List find(TaskSearch searchObject, Integer limit, Integer offset, S if (lastChangedSince != null) { query = query + "and lastModifiedTime>=:lastModifiedTime "; } - query = query + "ORDER BY pt.id ASC LIMIT :limit OFFSET :offset"; paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); paramsMap.put("lastModifiedTime", lastChangedSince); + + Long totalCount = CommonUtils.constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + + query = query + "ORDER BY pt.id ASC LIMIT :limit OFFSET :offset"; paramsMap.put("limit", limit); paramsMap.put("offset", offset); + List taskList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); fetchAndSetTaskResource(taskList); - return taskList; + + return SearchResponse.builder().response(taskList).totalCount(totalCount).build(); } private void fetchAndSetTaskResource(List taskList) { @@ -97,23 +109,26 @@ private void fetchAndSetTaskResource(List taskList) { taskList.forEach(task -> task.setResources(idToObjMap.get(task.getId()))); } - public List findById(List ids, String columnName, Boolean includeDeleted) { - List objFound = findInCache(ids).stream() - .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) - .collect(Collectors.toList()); + public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { + List objFound = findInCache(ids); + if (!includeDeleted) { + objFound = objFound.stream() + .filter(entity -> entity.getIsDeleted().equals(false)) + .collect(Collectors.toList()); + } if (!objFound.isEmpty()) { Method idMethod = getIdMethod(objFound, columnName); ids.removeAll(objFound.stream() .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) .collect(Collectors.toList())); if (ids.isEmpty()) { - return objFound; + return SearchResponse.builder().response(objFound).build(); } } - String query = String.format("SELECT * FROM project_task pt LEFT JOIN address a ON pt.addressid = a.id WHERE pt.%s IN (:ids) AND isDeleted = false", columnName); + String query = String.format("SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM project_task pt LEFT JOIN address a ON pt.addressid = a.id WHERE pt.%s IN (:ids) AND isDeleted = false", columnName); if (null != includeDeleted && includeDeleted) { - query = String.format("SELECT * FROM project_task pt LEFT JOIN address a ON pt.addressid = a.id WHERE pt.%s IN (:ids)", columnName); + query = String.format("SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM project_task pt LEFT JOIN address a ON pt.addressid = a.id WHERE pt.%s IN (:ids)", columnName); } Map paramMap = new HashMap<>(); paramMap.put("ids", ids); @@ -122,6 +137,7 @@ public List findById(List ids, String columnName, Boolean includeD fetchAndSetTaskResource(taskList); objFound.addAll(taskList); putInCache(objFound); - return objFound; + return SearchResponse.builder().response(objFound).build(); } + } diff --git a/health-services/project/src/main/java/org/egov/project/repository/UserActionRepository.java b/health-services/project/src/main/java/org/egov/project/repository/UserActionRepository.java new file mode 100644 index 00000000000..a5e61318fe8 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/repository/UserActionRepository.java @@ -0,0 +1,139 @@ +package org.egov.project.repository; + +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.builder.GenericQueryBuilder; +import org.egov.common.data.query.builder.QueryFieldChecker; +import org.egov.common.data.query.builder.SelectQueryBuilder; +import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionSearch; +import org.egov.common.producer.Producer; +import org.egov.common.utils.CommonUtils; +import org.egov.project.repository.rowmapper.UserActionRowMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdMethod; + +@Repository +@Slf4j +public class UserActionRepository extends GenericRepository { + + private final String selectQuery = + "SELECT id, clientreferenceid, tenantid, projectid, latitude, longitude, locationaccuracy, boundarycode, action, beneficiarytag, resourcetag, status, additionaldetails, createdby, createdtime, lastmodifiedby, lastmodifiedtime, clientcreatedtime, clientlastmodifiedtime, clientcreatedby, clientlastmodifiedby, rowversion FROM user_action ua"; + @Autowired + protected UserActionRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, + RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, + UserActionRowMapper rowMapper) { + super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, rowMapper, Optional.of("user_action")); + } + + /** + * Finds user actions based on search criteria and URL parameters. + * + * @param searchObject The search criteria for user actions. + * @param urlParams The URL parameters including pagination and filtering information. + * @return A SearchResponse containing the list of user actions and the total count. + * @throws QueryBuilderException If there is an error building the query. + */ + public SearchResponse find(UserActionSearch searchObject, URLParams urlParams) throws QueryBuilderException { + log.info("Executing find with searchObject: {} and urlParams: {}", searchObject, urlParams); + + String query = ""+selectQuery; + + Map paramsMap = new HashMap<>(); + List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); + query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); + query = query.replace("id IN (:id)", "ua.id IN (:id)"); + query = query.replace("clientReferenceId IN (:clientReferenceId)", "ua.clientReferenceId IN (:clientReferenceId)"); + + if (CollectionUtils.isEmpty(whereFields)) { + query = query + " WHERE ua.tenantId=:tenantId "; + } else { + query = query + " AND ua.tenantId=:tenantId "; + } + + if (urlParams.getLastChangedSince() != null) { + query = query + " AND lastModifiedTime>=:lastModifiedTime "; + } + paramsMap.put("tenantId", urlParams.getTenantId()); + paramsMap.put("isDeleted", urlParams.getIncludeDeleted()); + paramsMap.put("lastModifiedTime", urlParams.getLastChangedSince()); + + try { + log.debug("Executing query to fetch total count"); + Long totalCount = CommonUtils.constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + + query = query + " ORDER BY ua.id ASC LIMIT :limit OFFSET :offset"; + paramsMap.put("limit", urlParams.getLimit()); + paramsMap.put("offset", urlParams.getOffset()); + + log.debug("Executing query to fetch user actions: {}", query); + List userActionList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + + log.info("Successfully fetched user actions: {}", userActionList.size()); + return SearchResponse.builder().response(userActionList).totalCount(totalCount).build(); + } catch (Exception e) { + log.error("Failed to execute query for finding user actions", e); + return SearchResponse.builder().response(Collections.emptyList()).totalCount(0L).build(); + } + } + + /** + * Finds user actions by their IDs, first checking the cache before querying the database. + * + * @param ids The list of IDs to search for. + * @param columnName The name of the column to search by. + * @return A SearchResponse containing the list of user actions found. + */ + public SearchResponse findById(List ids, String columnName) { + log.info("Executing findById with ids: {} and columnName: {}", ids, columnName); + + List objFound = findInCache(ids); + + if (!objFound.isEmpty()) { + Method idMethod = getIdMethod(objFound, columnName); + ids.removeAll(objFound.stream() + .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) + .collect(Collectors.toList())); + + if (ids.isEmpty()) { + log.info("All requested user actions found in cache"); + return SearchResponse.builder().response(objFound).build(); + } + } + + String query = String.format(selectQuery + " WHERE ua.%s IN (:ids) ", columnName); + Map paramMap = new HashMap<>(); + paramMap.put("ids", ids); + + try { + log.debug("Executing query to fetch user actions by ID: {}", query); + List userActionList = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + + objFound.addAll(userActionList); + putInCache(objFound); + + log.info("Successfully fetched user actions by ID: {}", userActionList.size()); + return SearchResponse.builder().response(objFound).build(); + } catch (Exception e) { + log.error("Failed to execute query for finding user actions by ID", e); + return SearchResponse.builder().response(Collections.emptyList()).totalCount(0L).build(); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/repository/querybuilder/DocumentQueryBuilder.java b/health-services/project/src/main/java/org/egov/project/repository/querybuilder/DocumentQueryBuilder.java index 0e38e6f1173..3ef8383ab8a 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/querybuilder/DocumentQueryBuilder.java +++ b/health-services/project/src/main/java/org/egov/project/repository/querybuilder/DocumentQueryBuilder.java @@ -10,7 +10,7 @@ public class DocumentQueryBuilder { private static final String FETCH_DOCUMENT_QUERY = "select d.id as documentId, d.projectId as document_projectId, d.documentType as document_documentType, " + - " d.filestoreId as document_filestoreId, d.documentUid as document_documentUid, d.additionalDetails as document_additionalDetails, d.status as document_status, " + + " d.fileStoreId as document_fileStoreId, d.documentUid as document_documentUid, d.additionalDetails as document_additionalDetails, d.status as document_status, " + "d.createdBy as document_createdBy, d.createdTime as document_createdTime, d.lastModifiedBy as document_lastModifiedBy, d.lastModifiedTime as document_lastModifiedTime " + " from project_document d "; diff --git a/health-services/project/src/main/java/org/egov/project/repository/querybuilder/ProjectAddressQueryBuilder.java b/health-services/project/src/main/java/org/egov/project/repository/querybuilder/ProjectAddressQueryBuilder.java index eb623f877f0..466c3549af4 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/querybuilder/ProjectAddressQueryBuilder.java +++ b/health-services/project/src/main/java/org/egov/project/repository/querybuilder/ProjectAddressQueryBuilder.java @@ -1,14 +1,19 @@ package org.egov.project.repository.querybuilder; +import java.util.Collection; +import java.util.List; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.egov.common.models.core.ProjectSearchURLParams; import org.egov.common.models.project.Project; +import org.egov.common.models.project.ProjectSearch; import org.egov.project.config.ProjectConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; - -import java.util.Collection; -import java.util.List; +import org.springframework.util.CollectionUtils; import static org.egov.project.util.ProjectConstants.DOT; @@ -146,6 +151,129 @@ public String getProjectSearchQuery(List projects, Integer limit, Integ return addPaginationWrapper(queryBuilder.toString(), preparedStmtList, limit, offset); } + + /** + * Constructs the SQL query string for searching projects based on the given parameters. + * + * @param projectSearch The search criteria provided in the request body. + * @param urlParams The search criteria provided as URL parameters. + * @param preparedStmtList The list to which prepared statement parameters will be added. + * @param isCountQuery Boolean flag indicating if the query is for counting records. + * @return The constructed SQL query string. + */ + public String getProjectSearchQuery(@NotNull @Valid ProjectSearch projectSearch, ProjectSearchURLParams urlParams, List preparedStmtList, Boolean isCountQuery) { + // Use a ternary operator to select between PROJECTS_COUNT_QUERY and FETCH_PROJECT_ADDRESS_QUERY based on isCountQuery flag. + String query = isCountQuery ? PROJECTS_COUNT_QUERY : FETCH_PROJECT_ADDRESS_QUERY; + StringBuilder queryBuilder = new StringBuilder(query); + + // Check if tenant ID is provided in URL parameters + if (StringUtils.isNotBlank(urlParams.getTenantId())) { + addClauseIfRequired(preparedStmtList, queryBuilder); + if (!urlParams.getTenantId().contains(DOT)) { + // State level tenant ID: use LIKE for partial matching + log.info("State level tenant"); + queryBuilder.append(" prj.tenantId like ? "); + preparedStmtList.add(urlParams.getTenantId() + '%'); + } else { + // City level tenant ID: use exact match + log.info("City level tenant"); + queryBuilder.append(" prj.tenantId=? "); + preparedStmtList.add(urlParams.getTenantId()); + } + } + + // Check if project IDs are provided + if (!CollectionUtils.isEmpty(projectSearch.getId())) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.id IN (").append(createQuery(projectSearch.getId())).append(")"); + addToPreparedStatement(preparedStmtList, projectSearch.getId()); + } + + // Check if reference ID is provided + if (StringUtils.isNotBlank(projectSearch.getReferenceId())) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.referenceId =? "); + preparedStmtList.add(projectSearch.getReferenceId()); + } + + // Check if project name is provided + if (StringUtils.isNotBlank(projectSearch.getName())) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.name LIKE ? "); + preparedStmtList.add('%' + projectSearch.getName() + '%'); + } + + // Check if project type ID is provided + if (StringUtils.isNotBlank(projectSearch.getProjectTypeId())) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.projectType=? "); + preparedStmtList.add(projectSearch.getProjectTypeId()); + } + + // Check if boundary code is provided + if (projectSearch.getBoundaryCode() != null && StringUtils.isNotBlank(projectSearch.getBoundaryCode())) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" addr.boundary=? "); + preparedStmtList.add(projectSearch.getBoundaryCode()); + } + + // Check if sub-project type ID is provided + if (StringUtils.isNotBlank(projectSearch.getSubProjectTypeId())) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.projectSubtype=? "); + preparedStmtList.add(projectSearch.getSubProjectTypeId()); + } + + // Check if start date is provided + if (projectSearch.getStartDate() != null && projectSearch.getStartDate() != 0) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.startDate >= ? "); + preparedStmtList.add(projectSearch.getStartDate()); + } + + // Check if end date is provided + if (projectSearch.getEndDate() != null && projectSearch.getEndDate() != 0) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.endDate <= ? "); + preparedStmtList.add(projectSearch.getEndDate()); + } + + // Check if lastChangedSince is provided + if (urlParams.getLastChangedSince() != null && urlParams.getLastChangedSince() != 0) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" ( prj.lastModifiedTime >= ? )"); + preparedStmtList.add(urlParams.getLastChangedSince()); + } + + // Check if createdFrom date is provided + if (urlParams.getCreatedFrom() != null && urlParams.getCreatedFrom() != 0) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.createdTime >= ? "); + preparedStmtList.add(urlParams.getCreatedFrom()); + } + + // Check if createdTo date is provided + if (urlParams.getCreatedTo() != null && urlParams.getCreatedTo() != 0) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.createdTime <= ? "); + preparedStmtList.add(urlParams.getCreatedTo()); + } + + // Add clause if includeDeleted is true in request parameter + addIsDeletedCondition(preparedStmtList, queryBuilder, urlParams.getIncludeDeleted()); + + // Close the query with a closing bracket + queryBuilder.append(" )"); + + // Return query if it's a count query + if (isCountQuery) { + return queryBuilder.toString(); + } + + // Wrap constructed SQL query with pagination criteria + return addPaginationWrapper(queryBuilder.toString(), preparedStmtList, urlParams.getLimit(), urlParams.getOffset()); + } + /* Constructs project search query based on Project Ids */ public String getProjectSearchQueryBasedOnIds(List projectIds, List preparedStmtList) { StringBuilder queryBuilder = new StringBuilder(FETCH_PROJECT_ADDRESS_QUERY); @@ -244,4 +372,9 @@ public String getSearchCountQueryString(List projects, String tenantId, return query; } + /* Returns query to get total projects count based on project search params */ + public String getSearchCountQueryString(ProjectSearch projectSearch, ProjectSearchURLParams urlParams, List preparedStatement) { + String query = getProjectSearchQuery(projectSearch, urlParams, preparedStatement, Boolean.TRUE); + return query; + } } diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/DocumentRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/DocumentRowMapper.java index 6322ce82673..b9d3f814d7c 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/DocumentRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/DocumentRowMapper.java @@ -34,7 +34,7 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessE String document_id = rs.getString("documentId"); String document_projectId = rs.getString("document_projectId"); String document_documentType = rs.getString("document_documentType"); - String document_filestoreId = rs.getString("document_filestoreId"); + String document_fileStoreId = rs.getString("document_fileStoreId"); String document_documentUid = rs.getString("document_documentUid"); JsonNode document_additionalDetails = getAdditionalDetail("document_additionalDetails", rs); String document_status = rs.getString("document_status"); @@ -51,7 +51,7 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessE .id(document_id) .projectid(document_projectId) .documentType(document_documentType) - .fileStore(document_filestoreId) + .fileStoreId(document_fileStoreId) .documentUid(document_documentUid) .additionalDetails(document_additionalDetails) .status(document_status) diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java new file mode 100644 index 00000000000..b9ea8babec8 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java @@ -0,0 +1,91 @@ +package org.egov.project.repository.rowmapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.core.AdditionalFields; +import org.egov.common.models.project.UserActionEnum; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +/** + * RowMapper implementation for mapping rows of a ResultSet to UserAction objects. + * This class is used to map the result of a SQL query to UserAction instances. + */ +@Component +@Slf4j +public class LocationCaptureRowMapper implements RowMapper { + + private final ObjectMapper objectMapper; + + /** + * Constructor for dependency injection of ObjectMapper. + * + * @param objectMapper The ObjectMapper used for converting JSON strings to objects. + */ + @Autowired + public LocationCaptureRowMapper(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + /** + * Map a single row of the ResultSet to a UserAction object. + * + * @param resultSet The ResultSet containing data from the database. + * @param rowNum The number of the current row. + * @return A UserAction object populated with data from the current row of the ResultSet. + * @throws SQLException If there is an issue accessing the ResultSet data. + */ + @Override + public UserAction mapRow(ResultSet resultSet, int rowNum) throws SQLException { + + // Creating AuditDetails object with information from the ResultSet + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + + // Creating client-specific AuditDetails object with information from the ResultSet + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) + .build(); + + UserAction locationCaptureUserAction; + try { + // Building the UserAction object with data from the ResultSet + locationCaptureUserAction = UserAction.builder() + .id(resultSet.getString("id")) + .tenantId(resultSet.getString("tenantId")) + .clientReferenceId(resultSet.getString("clientReferenceId")) + .projectId(resultSet.getString("projectId")) + .latitude(resultSet.getDouble("latitude")) + .longitude(resultSet.getDouble("longitude")) + .locationAccuracy(resultSet.getDouble("locationAccuracy")) + .boundaryCode(resultSet.getString("boundaryCode")) + .action(UserActionEnum.fromValue(resultSet.getString("action"))) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) + .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper + .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) + .build(); + } catch (JsonProcessingException e) { + // Throwing a RuntimeException if there's an error processing JSON + log.error("Error processing Additional detail JSON in Location capture UserAction ", e); + throw new CustomException("HCM_PROJECT_USER_ACTION_LOCATION_CAPTURE_ROW_MAPPER_INVALID_ERROR", "Error processing JSON: " + e.getMessage()); + } + + return locationCaptureUserAction; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectAddressRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectAddressRowMapper.java index 2e8d69f961f..fa5d72c5dc7 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectAddressRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectAddressRowMapper.java @@ -87,6 +87,10 @@ private Address getAddressObjFromResultSet(ResultSet rs) throws SQLException { .boundary(address_boundary) .build(); + if (address_id == null) { + return null; + } + return address; } diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java index 64e07258a2f..c79c91ed161 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.project.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectBeneficiary; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; @@ -19,6 +19,18 @@ public class ProjectBeneficiaryRowMapper implements RowMapper { diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java index 5403b3a00cc..a0ff3d24bcf 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java @@ -1,16 +1,16 @@ package org.egov.project.repository.rowmapper; +import java.sql.ResultSet; +import java.sql.SQLException; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.project.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectStaff; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import java.sql.ResultSet; -import java.sql.SQLException; - @Component public class ProjectStaffRowMapper implements RowMapper { diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java index af4c05002d4..ccff648bd41 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java @@ -3,11 +3,12 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.project.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.Address; import org.egov.common.models.project.AddressType; -import org.egov.common.models.project.Boundary; +import org.egov.common.models.core.Boundary; import org.egov.common.models.project.Task; +import org.egov.common.models.project.TaskStatus; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; @@ -22,7 +23,19 @@ public class ProjectTaskRowMapper implements RowMapper { @Override public Task mapRow(ResultSet resultSet, int i) throws SQLException { try { - return Task.builder() + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) + .build(); + Task task = Task.builder() .id(resultSet.getString("id")) .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) @@ -35,19 +48,15 @@ public Task mapRow(ResultSet resultSet, int i) throws SQLException { .plannedEndDate(resultSet.getLong("plannedEndDate")) .actualStartDate(resultSet.getLong("actualStartDate")) .actualEndDate(resultSet.getLong("actualEndDate")) - .status(resultSet.getString("status")) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) + .status(TaskStatus.fromValue(resultSet.getString("status"))) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) .address(Address.builder() - .id(resultSet.getString(20)) - .tenantId(resultSet.getString(21)) - .clientReferenceId(resultSet.getString(35)) + .id(resultSet.getString("aid")) + .tenantId(resultSet.getString("atenantid")) + .clientReferenceId(resultSet.getString("aclientreferenceid")) .doorNo(resultSet.getString("doorNo")) .latitude(resultSet.getDouble("latitude")) .longitude(resultSet.getDouble("longitude")) @@ -60,11 +69,16 @@ public Task mapRow(ResultSet resultSet, int i) throws SQLException { .pincode(resultSet.getString("pinCode")) .buildingName(resultSet.getString("buildingName")) .street(resultSet.getString("street")) - .locality(Boundary.builder().code(resultSet.getString("localityCode")).build()) + .locality(resultSet.getString("localityCode") != null ? + Boundary.builder().code(resultSet.getString("localityCode")).build() : null) .build()) .build(); + if (task.getAddress().getId() == null) { + task.setAddress(null); + } + return task; } catch (JsonProcessingException e) { throw new SQLException(e); } } -} \ No newline at end of file +} 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 51a45703e65..87cab062d9c 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TaskResourceRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TaskResourceRowMapper.java @@ -1,6 +1,9 @@ package org.egov.project.repository.rowmapper; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.TaskResource; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; @@ -11,24 +14,33 @@ @Component public class TaskResourceRowMapper implements RowMapper { + private final ObjectMapper objectMapper = new ObjectMapper(); + @Override public TaskResource mapRow(ResultSet resultSet, int i) throws SQLException { - return TaskResource.builder() - .id(resultSet.getString("id")) - .isDeleted(resultSet.getBoolean("isDeleted")) - .tenantId(resultSet.getString("tenantId")) - .taskId(resultSet.getString("taskId")) - .productVariantId(resultSet.getString("productVariantId")) - .quantity(resultSet.getLong("quantity")) - .isDelivered(resultSet.getBoolean("isDelivered")) - .deliveryComment(resultSet.getString("isDelivered")) - .clientReferenceId(resultSet.getString("clientReferenceId")) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) - .build(); + try { + return TaskResource.builder() + .id(resultSet.getString("id")) + .isDeleted(resultSet.getBoolean("isDeleted")) + .tenantId(resultSet.getString("tenantId")) + .taskId(resultSet.getString("taskId")) + .productVariantId(resultSet.getString("productVariantId")) + .quantity(resultSet.getDouble("quantity")) + .isDelivered(resultSet.getBoolean("isDelivered")) + .deliveryComment(resultSet.getString("reasonIfNotDelivered")) + .clientReferenceId(resultSet.getString("clientReferenceId")) + .auditDetails(AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build()) + .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper + .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) + .build(); + } catch ( + JsonProcessingException e) { + throw new SQLException(e); + } } } diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java new file mode 100644 index 00000000000..8a63f0f3c99 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java @@ -0,0 +1,94 @@ +package org.egov.project.repository.rowmapper; + +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.core.AdditionalFields; +import org.egov.common.models.project.UserActionEnum; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +/** + * RowMapper implementation for mapping rows of a ResultSet to UserAction objects. + * This class is used to map the result of a SQL query to UserAction instances. + */ +@Component +@Slf4j +public class UserActionRowMapper implements RowMapper { + + private final ObjectMapper objectMapper; + + /** + * Constructor for dependency injection of ObjectMapper. + * + * @param objectMapper The ObjectMapper used for converting JSON strings to objects. + */ + @Autowired + public UserActionRowMapper(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + /** + * Map a single row of the ResultSet to a UserAction object. + * + * @param resultSet The ResultSet containing data from the database. + * @param rowNum The number of the current row. + * @return A UserAction object populated with data from the current row of the ResultSet. + * @throws SQLException If there is an issue accessing the ResultSet data or processing JSON. + */ + @Override + public UserAction mapRow(ResultSet resultSet, int rowNum) throws SQLException { + try { + // Creating AuditDetails object with information from the ResultSet + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + + // Creating client-specific AuditDetails object with information from the ResultSet + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) + .build(); + + // Building the UserAction object with data from the ResultSet + UserAction userAction = UserAction.builder() + .id(resultSet.getString("id")) + .tenantId(resultSet.getString("tenantId")) + .clientReferenceId(resultSet.getString("clientReferenceId")) + .projectId(resultSet.getString("projectId")) + .latitude(resultSet.getDouble("latitude")) + .longitude(resultSet.getDouble("longitude")) + .locationAccuracy(resultSet.getDouble("locationAccuracy")) + .boundaryCode(resultSet.getString("boundaryCode")) + .action(UserActionEnum.fromValue(resultSet.getString("action"))) + .beneficiaryTag(resultSet.getString("beneficiaryTag")) + .resourceTag(resultSet.getString("resourceTag")) + .rowVersion(resultSet.getInt("rowVersion")) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) + .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper + .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) + .build(); + + return userAction; + } catch (JsonProcessingException e) { + String id = resultSet.getString("id"); + String errorMessage = "Error processing JSON for UserAction mapping. Row number: " + rowNum + ", id: " + (id != null ? id : "not available"); + log.error(errorMessage, e); + throw new CustomException("HCM_PROJECT_USER_ACTION_ROW_MAPPER_INVALID_ERROR", errorMessage + ", " + e.getMessage()); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/service/LocationCaptureService.java b/health-services/project/src/main/java/org/egov/project/service/LocationCaptureService.java new file mode 100644 index 00000000000..5667184beb0 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/service/LocationCaptureService.java @@ -0,0 +1,222 @@ +package org.egov.project.service; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.ds.Tuple; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.models.project.useraction.UserActionSearch; +import org.egov.common.models.project.useraction.UserActionSearchRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.common.validator.Validator; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.repository.LocationCaptureRepository; +import org.egov.project.service.enrichment.UserActionEnrichmentService; +import org.egov.project.validator.useraction.UaBoundaryValidator; +import org.egov.project.validator.useraction.UaExistentEntityValidator; +import org.egov.project.validator.useraction.UaProjectIdValidator; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.project.Constants.SET_USER_ACTION; +import static org.egov.project.Constants.VALIDATION_ERROR; + +/** + * Service class for handling location capture tasks related to user actions. + * Provides methods for creating, validating, searching, and caching location capture tasks. + */ +@Service +@Slf4j +public class LocationCaptureService { + + private final IdGenService idGenService; + private final LocationCaptureRepository locationCaptureRepository; + private final ServiceRequestClient serviceRequestClient; + private final ProjectConfiguration projectConfiguration; + private final UserActionEnrichmentService userActionEnrichmentService; + private final List> validators; + + /** + * Predicate to determine if a validator is applicable for creation. + * Filters validators based on specific classes. + */ + private final Predicate> isApplicableForCreate = validator -> + validator.getClass().equals(UaProjectIdValidator.class) + || validator.getClass().equals(UaExistentEntityValidator.class) + || validator.getClass().equals(UaBoundaryValidator.class); + + /** + * Constructor for injecting dependencies into the LocationCaptureService. + * + * @param idGenService The service for generating unique IDs. + * @param locationCaptureRepository Repository for location capture tasks. + * @param serviceRequestClient Client for making service requests. + * @param projectConfiguration Configuration properties related to the project. + * @param userActionEnrichmentService Service for enriching location capture user action tasks. + * @param validators List of validators for user actions. + */ + @Autowired + public LocationCaptureService( + IdGenService idGenService, + LocationCaptureRepository locationCaptureRepository, + ServiceRequestClient serviceRequestClient, + ProjectConfiguration projectConfiguration, + UserActionEnrichmentService userActionEnrichmentService, + List> validators + ) { + this.idGenService = idGenService; + this.locationCaptureRepository = locationCaptureRepository; + this.serviceRequestClient = serviceRequestClient; + this.projectConfiguration = projectConfiguration; + this.userActionEnrichmentService = userActionEnrichmentService; + this.validators = validators; + } + + /** + * Creates location capture tasks in bulk. + * Validates the request, enriches valid tasks, saves them, and handles errors. + * + * @param request The bulk request containing location capture tasks. + * @param isBulk Flag indicating if the request is a bulk operation. + * @return A list of valid location capture tasks. + */ + public List create(UserActionBulkRequest request, boolean isBulk) { + log.info("Received request to create bulk location capture tasks"); + + // Validate the request and separate valid tasks from error details. + Tuple, Map> tuple = validate(validators, isApplicableForCreate, request, isBulk); + Map errorDetailsMap = tuple.getY(); + List validLocationCaptures = tuple.getX(); + + try { + if (!validLocationCaptures.isEmpty()) { + log.info("Processing {} valid entities", validLocationCaptures.size()); + + // Enrich valid location capture tasks. + userActionEnrichmentService.create(validLocationCaptures, request); + + // Save valid location capture tasks and send them to the Kafka topic. + locationCaptureRepository.save(validLocationCaptures, projectConfiguration.getCreateLocationCaptureTopic()); + log.info("Successfully created location capture tasks"); + } + } catch (Exception exception) { + // Log and handle exceptions that occur during task creation. + log.error("Error occurred while creating location capture tasks: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validLocationCaptures, exception, SET_USER_ACTION); + } + + // Handle errors based on the validation results. + handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); + + return validLocationCaptures; + } + + /** + * Validates the user action bulk request using the provided validators. + * Filters out tasks with errors and returns the valid ones. + * + * @param validators List of validators to use for validation. + * @param applicableValidators Predicate to filter applicable validators. + * @param request The bulk request to validate. + * @param isBulk Flag indicating if the request is a bulk operation. + * @return A tuple containing valid location capture tasks and error details. + */ + private Tuple, Map> validate( + List> validators, + Predicate> applicableValidators, + UserActionBulkRequest request, boolean isBulk) { + + log.info("Validating request"); + + // Perform validation and collect error details. + Map errorDetailsMap = CommonUtils.validate( + validators, + applicableValidators, + request, + SET_USER_ACTION + ); + + // Throw an exception if there are validation errors and it's not a bulk operation. + if (!errorDetailsMap.isEmpty() && !isBulk) { + throw new CustomException(VALIDATION_ERROR, errorDetailsMap.values().toString()); + } + + // Filter out tasks with no errors. + List validLocationCaptures = request.getUserActions().stream() + .filter(notHavingErrors()) + .collect(Collectors.toList()); + + return new Tuple<>(validLocationCaptures, errorDetailsMap); + } + + /** + * Searches for location capture tasks based on the provided search request and URL parameters. + * Supports searching by ID or by other criteria. + * + * @param locationCaptureSearchRequest The search request containing criteria for searching. + * @param urlParams URL parameters for filtering the search results. + * @return A SearchResponse containing the search results and total count. + */ + public SearchResponse search(UserActionSearchRequest locationCaptureSearchRequest, URLParams urlParams) { + log.info("Received request to search project task"); + + UserActionSearch locationCaptureSearch = locationCaptureSearchRequest.getUserAction(); + String idFieldName = getIdFieldName(locationCaptureSearch); + + if (isSearchByIdOnly(locationCaptureSearch, idFieldName)) { + log.info("Searching location capture by id"); + List ids = (List) ReflectionUtils.invokeMethod( + getIdMethod(Collections.singletonList(locationCaptureSearch)), + locationCaptureSearch + ); + log.info("Fetching location capture tasks with ids: {}", ids); + + // Perform search by IDs and filter results based on last changed date and tenant ID. + SearchResponse searchResponse = locationCaptureRepository.findById(ids, idFieldName); + return SearchResponse.builder() + .response(searchResponse.getResponse().stream() + .filter(lastChangedSince(urlParams.getLastChangedSince())) + .filter(havingTenantId(urlParams.getTenantId())) + .collect(Collectors.toList()) + ) + .totalCount(searchResponse.getTotalCount()) + .build(); + } + + log.info("Searching project beneficiaries using criteria"); + // Perform search based on other criteria. + return locationCaptureRepository.find(locationCaptureSearch, urlParams); + } + + /** + * Puts location capture tasks into cache. + * + * @param locationCaptures The list of location capture tasks to cache. + */ + public void putInCache(List locationCaptures) { + log.info("Putting {} location tracking tasks in cache", locationCaptures.size()); + locationCaptureRepository.putInCache(locationCaptures); + log.info("Successfully put location tracking tasks in cache"); + } +} diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectBeneficiaryService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectBeneficiaryService.java index 11d094561c4..73d70127632 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectBeneficiaryService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectBeneficiaryService.java @@ -1,10 +1,19 @@ 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.BeneficiaryBulkRequest; import org.egov.common.models.project.BeneficiaryRequest; +import org.egov.common.models.project.BeneficiarySearchRequest; import org.egov.common.models.project.ProjectBeneficiary; import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; @@ -13,24 +22,21 @@ import org.egov.project.repository.ProjectBeneficiaryRepository; import org.egov.project.service.enrichment.ProjectBeneficiaryEnrichmentService; import org.egov.project.validator.beneficiary.BeneficiaryValidator; +import org.egov.project.validator.beneficiary.PbExistentEntityValidator; import org.egov.project.validator.beneficiary.PbIsDeletedValidator; import org.egov.project.validator.beneficiary.PbNonExistentEntityValidator; import org.egov.project.validator.beneficiary.PbNullIdValidator; import org.egov.project.validator.beneficiary.PbProjectIdValidator; import org.egov.project.validator.beneficiary.PbRowVersionValidator; import org.egov.project.validator.beneficiary.PbUniqueEntityValidator; -import org.egov.project.web.models.BeneficiarySearchRequest; +import org.egov.project.validator.beneficiary.PbUniqueTagsValidator; +import org.egov.project.validator.beneficiary.PbVoucherTagUniqueForCreateValidator; +import org.egov.project.validator.beneficiary.PbVoucherTagUniqueForUpdateValidator; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdMethod; import static org.egov.common.utils.CommonUtils.handleErrors; @@ -62,6 +68,8 @@ public class ProjectBeneficiaryService { private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(PbNullIdValidator.class) || validator.getClass().equals(PbNonExistentEntityValidator.class) + || validator.getClass().equals(PbUniqueTagsValidator.class) + || validator.getClass().equals(PbVoucherTagUniqueForUpdateValidator.class) || validator.getClass().equals(PbIsDeletedValidator.class) || validator.getClass().equals(PbProjectIdValidator.class) || validator.getClass().equals(BeneficiaryValidator.class) @@ -70,7 +78,10 @@ public class ProjectBeneficiaryService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(PbProjectIdValidator.class) - || validator.getClass().equals(BeneficiaryValidator.class); + || validator.getClass().equals(PbExistentEntityValidator.class) + || validator.getClass().equals(BeneficiaryValidator.class) + || validator.getClass().equals(PbUniqueTagsValidator.class) + || validator.getClass().equals(PbVoucherTagUniqueForCreateValidator.class); private final Predicate> isApplicableForDelete = validator -> validator.getClass().equals(PbNullIdValidator.class) @@ -117,7 +128,7 @@ public List create(BeneficiaryBulkRequest beneficiaryRequest log.info("successfully created project beneficiaries"); } } catch (Exception exception) { - log.error("error occurred while creating project beneficiaries: {}", exception.getMessage()); + log.error("error occurred while creating project beneficiaries: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(beneficiaryRequest, errorDetailsMap, validProjectBeneficiaries, exception, SET_PROJECT_BENEFICIARIES); } @@ -150,7 +161,7 @@ public List update(BeneficiaryBulkRequest beneficiaryRequest log.info("successfully updated bulk project beneficiaries"); } } catch (Exception exception) { - log.error("error occurred while updating project beneficiaries", exception); + log.error("error occurred while updating project beneficiaries", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(beneficiaryRequest, errorDetailsMap, validProjectBeneficiaries, exception, SET_PROJECT_BENEFICIARIES); } @@ -159,12 +170,12 @@ public List update(BeneficiaryBulkRequest beneficiaryRequest return validProjectBeneficiaries; } - public List search(BeneficiarySearchRequest beneficiarySearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { + public SearchResponse search(BeneficiarySearchRequest beneficiarySearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { log.info("received request to search project beneficiaries"); String idFieldName = getIdFieldName(beneficiarySearchRequest.getProjectBeneficiary()); if (isSearchByIdOnly(beneficiarySearchRequest.getProjectBeneficiary(), idFieldName)) { @@ -173,11 +184,17 @@ public List search(BeneficiarySearchRequest beneficiarySearc .singletonList(beneficiarySearchRequest.getProjectBeneficiary())), beneficiarySearchRequest.getProjectBeneficiary()); log.info("fetching project beneficiaries with ids: {}", ids); - return projectBeneficiaryRepository.findById(ids, includeDeleted, idFieldName).stream() + + SearchResponse searchResponse = projectBeneficiaryRepository.findById(ids, idFieldName, includeDeleted); + + List projectBeneficiaries = searchResponse.getResponse().stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); + searchResponse.setResponse(projectBeneficiaries); + + return searchResponse; } log.info("searching project beneficiaries using criteria"); return projectBeneficiaryRepository.find(beneficiarySearchRequest.getProjectBeneficiary(), @@ -207,7 +224,7 @@ public List delete(BeneficiaryBulkRequest beneficiaryRequest log.info("successfully deleted entities"); } } catch (Exception exception) { - log.error("error occurred while deleting entities: {}", exception); + log.error("error occurred while deleting entities: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(beneficiaryRequest, errorDetailsMap, validProjectBeneficiaries, exception, SET_PROJECT_BENEFICIARIES); } diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java index 9074b22bdf9..f7628318789 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java @@ -1,11 +1,13 @@ package org.egov.project.service; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.project.ProjectFacility; import org.egov.common.models.project.ProjectFacilityBulkRequest; import org.egov.common.models.project.ProjectFacilityRequest; +import org.egov.common.models.project.ProjectFacilitySearchRequest; import org.egov.common.service.IdGenService; import org.egov.common.service.UserService; import org.egov.common.utils.CommonUtils; @@ -21,7 +23,6 @@ import org.egov.project.validator.facility.PfRowVersionValidator; import org.egov.project.validator.facility.PfUniqueCombinationValidator; import org.egov.project.validator.facility.PfUniqueEntityValidator; -import org.egov.project.web.models.ProjectFacilitySearchRequest; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -121,7 +122,7 @@ public List create(ProjectFacilityBulkRequest request, boolean log.info("successfully created project facility"); } } catch (Exception exception) { - log.error("error occurred while creating project facility: {}", exception.getMessage()); + log.error("error occurred while creating project facility: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_PROJECT_FACILITIES); } @@ -155,7 +156,7 @@ public List update(ProjectFacilityBulkRequest request, boolean log.info("successfully updated bulk project facility"); } } catch (Exception exception) { - log.error("error occurred while updating project facility", exception); + log.error("error occurred while updating project facility", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_PROJECT_FACILITIES); } @@ -187,7 +188,7 @@ public List delete(ProjectFacilityBulkRequest request, boolean log.info("successfully deleted entities"); } } catch (Exception exception) { - log.error("error occurred while deleting entities: {}", exception); + log.error("error occurred while deleting entities: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_PROJECT_FACILITIES); } diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java index 9fc3ec389db..660efbd4814 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java @@ -1,6 +1,7 @@ package org.egov.project.service; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; @@ -19,7 +20,7 @@ import org.egov.project.validator.resource.PrRowVersionValidator; import org.egov.project.validator.resource.PrUniqueCombinationValidator; import org.egov.project.validator.resource.PrUniqueEntityValidator; -import org.egov.project.web.models.ProjectResourceSearchRequest; +import org.egov.common.models.project.ProjectResourceSearchRequest; import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; @@ -105,7 +106,7 @@ public List create(ProjectResourceBulkRequest request, boolean log.info("successfully created project resource"); } } catch (Exception exception) { - log.error("error occurred while creating project resource: {}", exception.getMessage()); + log.error("error occurred while creating project resource: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_PROJECT_RESOURCE); } @@ -138,7 +139,7 @@ public List update(ProjectResourceBulkRequest request, boolean log.info("successfully created project resource"); } } catch (Exception exception) { - log.error("error occurred while creating project resource: {}", exception.getMessage()); + log.error("error occurred while creating project resource: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_PROJECT_RESOURCE); } @@ -171,7 +172,7 @@ public List delete(ProjectResourceBulkRequest request, boolean log.info("successfully deleted project resource"); } } catch (Exception exception) { - log.error("error occurred while deleting project resource: {}", exception.getMessage()); + log.error("error occurred while deleting project resource: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_PROJECT_RESOURCE); } diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectService.java index 73be7441812..56e2665792a 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectService.java @@ -1,15 +1,23 @@ package org.egov.project.service; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import jakarta.validation.Valid; +import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.ProjectSearchURLParams; import org.egov.common.models.project.Project; import org.egov.common.models.project.ProjectRequest; +import org.egov.common.models.project.ProjectSearchRequest; import org.egov.common.producer.Producer; import org.egov.project.config.ProjectConfiguration; import org.egov.project.repository.ProjectRepository; import org.egov.project.service.enrichment.ProjectEnrichment; +import org.egov.project.util.ProjectServiceUtil; import org.egov.project.validator.project.ProjectValidator; +import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -21,6 +29,7 @@ @Slf4j public class ProjectService { + private final ProjectRepository projectRepository; private final ProjectValidator projectValidator; @@ -31,15 +40,21 @@ public class ProjectService { private final Producer producer; + private final ProjectServiceUtil projectServiceUtil; + + private final ObjectMapper objectMapper; + @Autowired public ProjectService( ProjectRepository projectRepository, - ProjectValidator projectValidator, ProjectEnrichment projectEnrichment, ProjectConfiguration projectConfiguration, Producer producer) { + ProjectValidator projectValidator, ProjectEnrichment projectEnrichment, ProjectConfiguration projectConfiguration, Producer producer,ProjectServiceUtil projectServiceUtil) { this.projectRepository = projectRepository; this.projectValidator = projectValidator; this.projectEnrichment = projectEnrichment; this.projectConfiguration = projectConfiguration; this.producer = producer; + this.projectServiceUtil = projectServiceUtil; + this.objectMapper = new ObjectMapper(); } public List validateProjectIds(List productIds) { @@ -64,28 +79,223 @@ public ProjectRequest createProject(ProjectRequest projectRequest) { return projectRequest; } - public List searchProject(ProjectRequest project, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted, Boolean includeAncestors, Boolean includeDescendants, Long createdFrom, Long createdTo) { + public List searchProject( + ProjectRequest project, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted, + Boolean includeAncestors, + Boolean includeDescendants, + Long createdFrom, + Long createdTo + ) { projectValidator.validateSearchProjectRequest(project, limit, offset, tenantId, createdFrom, createdTo); - List projects = projectRepository.getProjects(project, limit, offset, tenantId, lastChangedSince, includeDeleted, includeAncestors, includeDescendants, createdFrom, createdTo); + List projects = projectRepository.getProjects( + project, + limit, + offset, + tenantId, + lastChangedSince, + includeDeleted, + includeAncestors, + includeDescendants, + createdFrom, + createdTo + ); return projects; } - public ProjectRequest updateProject(ProjectRequest project) { - projectValidator.validateUpdateProjectRequest(project); + public List searchProject(ProjectSearchRequest projectSearchRequest, @Valid ProjectSearchURLParams urlParams) { + projectValidator.validateSearchV2ProjectRequest(projectSearchRequest, urlParams); + return projectRepository.getProjects(projectSearchRequest.getProject(), urlParams); + } + + public ProjectRequest updateProject(ProjectRequest request) { + /* + * Validate the update project request + */ + projectValidator.validateUpdateProjectRequest(request); log.info("Update project request validated"); - //Search projects based on project ids - List projectsFromDB = searchProject(getSearchProjectRequest(project.getProjects(), project.getRequestInfo(), false), projectConfiguration.getMaxLimit(), projectConfiguration.getDefaultOffset(), project.getProjects().get(0).getTenantId(), null, false, false, false, null, null); + + /* + * Search for projects based on project IDs provided in the request + */ + List projectsFromDB = searchProject( + getSearchProjectRequest(request.getProjects(), request.getRequestInfo(), false), + projectConfiguration.getMaxLimit(), projectConfiguration.getDefaultOffset(), + request.getProjects().get(0).getTenantId(), null, false, false, false, null, null + ); log.info("Fetched projects for update request"); - //Validate Update project request against projects fetched form database - projectValidator.validateUpdateAgainstDB(project.getProjects(), projectsFromDB); - projectEnrichment.enrichProjectOnUpdate(project, projectsFromDB); - log.info("Enriched with project Number, Ids and AuditDetails"); - producer.push(projectConfiguration.getUpdateProjectTopic(), project); - log.info("Pushed to kafka"); - return project; + /* + * Validate the update project request against the projects fetched from the database + */ + projectValidator.validateUpdateAgainstDB(request.getProjects(), projectsFromDB); + + /* + * Process each project in the update request + */ + for (Project project : request.getProjects()) { + processProjectUpdate(request, project, projectsFromDB); + } + + return request; + } + + private void processProjectUpdate(ProjectRequest request, Project project, List projectsFromDB) { + /* + * Convert project ID to string for comparison + */ + String projectId = String.valueOf(project.getId()); + + /* + * Find the project from the database that matches the current project ID + */ + Project projectFromDB = findProjectById(projectId, projectsFromDB); + boolean isCascadingProjectDateUpdate = request.isCascadingProjectDateUpdate(); + + if (projectFromDB != null) { + /* + * Merge additional details of the project from the request and project from DB + */ + projectServiceUtil.mergeAdditionalDetails(project, projectFromDB); + + /* + * Handle cases where cascading project date update is true + */ + if (isCascadingProjectDateUpdate) { + handleUpdateProjectDates(request, project, projectFromDB); + } + /* + * Handle cases for normal update flow + */ + else { + handleNormalUpdate(request, project, projectFromDB); + } + } + } + + private Project findProjectById(String projectId, List projectsFromDB) { + /* + * Find and return the project with the matching ID from the list of projects fetched from the database + */ + return projectsFromDB.stream() + .filter(p -> projectId.equals(String.valueOf(p.getId()))) + .findFirst() + .orElse(null); + } + + + private void handleNormalUpdate(ProjectRequest request, Project project, Project projectFromDB) { + /* + * Ensure that start and end dates are not being updated when flag is false + */ + if (!project.getStartDate().equals(projectFromDB.getStartDate()) || + !project.getEndDate().equals(projectFromDB.getEndDate())) { + throw new CustomException("PROJECT_CASCADE_UPDATE_DATE_ERROR", + "Can't Update Date Range if Cascade Project Date Update false"); + } + + /* + * Enrich the project with values other than the start, end dates, and AdditionalDetails, + * and push the update to the message broker + */ + projectEnrichment.enrichProjectOnUpdate(request, project, projectFromDB); + producer.push(projectConfiguration.getUpdateProjectTopic(), request); + } + + private void handleUpdateProjectDates(ProjectRequest request, Project project, Project projectFromDB) { + /* + * Save original values of start date, end date, and additional details + */ + Long originalStartDate = projectFromDB.getStartDate(); + Long originalEndDate = projectFromDB.getEndDate(); + Object originalAdditionalDetails = projectFromDB.getAdditionalDetails(); + AuditDetails originalAuditDetails = projectFromDB.getAuditDetails(); + + + /* + * Update the project with new start date, end date, and additional details + */ + projectFromDB.setStartDate(project.getStartDate()); + projectFromDB.setEndDate(project.getEndDate()); + projectFromDB.setAdditionalDetails(project.getAdditionalDetails()); + projectFromDB.setAuditDetails(project.getAuditDetails()); + + /* + * Ensure that no other properties are being updated besides the start and end dates + */ + if (!objectMapper.valueToTree(projectFromDB).equals(objectMapper.valueToTree(project))) { + throw new CustomException( + "PROJECT_CASCADE_UPDATE_ERROR", + "Can only update Project dates and additional details if cascade Project date update true" + ); + } + + /* + * Restore original values of start date, end date, and additional details + */ + projectFromDB.setStartDate(originalStartDate); + projectFromDB.setEndDate(originalEndDate); + projectFromDB.setAdditionalDetails(originalAdditionalDetails); + projectFromDB.setAuditDetails(originalAuditDetails); + + /* + * Update lastModifiedTime and lastModifiedBy for the project + */ + projectEnrichment.enrichProjectRequestOnUpdate(project, projectFromDB, request.getRequestInfo()); + + /* + * Check and enrich cascading project dates and push the update to the message broker + */ + checkAndEnrichCascadingProjectDates(request, project); + producer.push(projectConfiguration.getUpdateProjectDateTopic(), request); + } + + + /** + * Checks and enriches cascading project dates. + * + * @param request The project request containing projects and request information. + */ + private void checkAndEnrichCascadingProjectDates(ProjectRequest request, Project project) { + /* + * Retrieve tenant ID from the first project in the request + */ + String tenantId = request.getProjects().get(0).getTenantId(); + String projectId = String.valueOf(project.getId()); + + /* + * Fetch projects from the database with ancestors and descendants + */ + List projectsFromDbWithAncestorsAndDescendants = searchProject( + getSearchProjectRequest(request.getProjects(), request.getRequestInfo(), false), + projectConfiguration.getMaxLimit(), + projectConfiguration.getDefaultOffset(), + tenantId, + null, + false, + true, + true, + null, + null + ); + + /* + * Create a map of projects from the database with ancestors and descendants + */ + Map projectFromDbWithAncestorsAndDescendantsMap = projectServiceUtil.createProjectMap(projectsFromDbWithAncestorsAndDescendants); + Project projectFromDbWithAncestorsAndDescendants = projectFromDbWithAncestorsAndDescendantsMap.get(projectId); + + /* + * Enrich project cascading dates based on the retrieved data + */ + projectEnrichment.enrichProjectCascadingDatesOnUpdate(project, projectFromDbWithAncestorsAndDescendants); } + /* Search for parent projects based on "parent" field and returns parent projects */ private List getParentProjects(ProjectRequest projectRequest) { List parentProjects = null; @@ -122,4 +332,9 @@ private ProjectRequest getSearchProjectRequest(List projects, RequestIn public Integer countAllProjects(ProjectRequest project, String tenantId, Long lastChangedSince, Boolean includeDeleted, Long createdFrom, Long createdTo) { return projectRepository.getProjectCount(project, tenantId, lastChangedSince, includeDeleted, createdFrom, createdTo); } + + + public Integer countAllProjects(ProjectSearchRequest projectSearchRequest, ProjectSearchURLParams urlParams) { + return projectRepository.getProjectCount(projectSearchRequest.getProject(), urlParams); + } } diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java index 3c299826c90..c600537a74e 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java @@ -1,11 +1,13 @@ package org.egov.project.service; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.project.ProjectStaff; import org.egov.common.models.project.ProjectStaffBulkRequest; import org.egov.common.models.project.ProjectStaffRequest; +import org.egov.common.producer.Producer; import org.egov.common.service.IdGenService; import org.egov.common.service.UserService; import org.egov.common.utils.CommonUtils; @@ -21,12 +23,14 @@ import org.egov.project.validator.staff.PsUniqueCombinationValidator; import org.egov.project.validator.staff.PsUniqueEntityValidator; import org.egov.project.validator.staff.PsUserIdValidator; -import org.egov.project.web.models.ProjectStaffSearchRequest; +import org.egov.common.models.project.ProjectStaffSearchRequest; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.lang.reflect.Type; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Predicate; @@ -60,6 +64,8 @@ public class ProjectStaffService { private final List> validators; + private final Producer producer; + private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(PsUserIdValidator.class) || validator.getClass().equals(PsProjectIdValidator.class) @@ -86,7 +92,8 @@ public ProjectStaffService( ProjectService projectService, UserService userService, ProjectConfiguration projectConfiguration, - ProjectStaffEnrichmentService enrichmentService, List> validators) { + ProjectStaffEnrichmentService enrichmentService, + Producer producer, List> validators) { this.idGenService = idGenService; this.projectStaffRepository = projectStaffRepository; this.projectService = projectService; @@ -94,6 +101,7 @@ public ProjectStaffService( this.projectConfiguration = projectConfiguration; this.enrichmentService = enrichmentService; this.validators = validators; + this.producer = producer; } public ProjectStaff create(ProjectStaffRequest request) { @@ -117,11 +125,14 @@ public List create(ProjectStaffBulkRequest request, boolean isBulk if (!validEntities.isEmpty()) { log.info("processing {} valid entities", validEntities.size()); enrichmentService.create(validEntities, request); + // Pushing the data as ProjectStaffBulkRequest for Attendance Service Consumer + producer.push(projectConfiguration.getProjectStaffAttendanceTopic(), new ProjectStaffBulkRequest(request.getRequestInfo(),validEntities)); + // Pushing the data as list for persister consumer projectStaffRepository.save(validEntities, projectConfiguration.getCreateProjectStaffTopic()); log.info("successfully created project staff"); } } catch (Exception exception) { - log.error("error occurred while creating project staff: {}", exception.getMessage()); + log.error("error occurred while creating project staff: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_STAFF); } @@ -155,7 +166,7 @@ public List update(ProjectStaffBulkRequest request, boolean isBulk log.info("successfully updated bulk project staff"); } } catch (Exception exception) { - log.error("error occurred while updating project staff", exception); + log.error("error occurred while updating project staff", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_STAFF); } @@ -187,7 +198,7 @@ public List delete(ProjectStaffBulkRequest request, boolean isBulk log.info("successfully deleted entities"); } } catch (Exception exception) { - log.error("error occurred while deleting entities: {}", exception); + log.error("error occurred while deleting entities: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_STAFF); } diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java index 90be2dcf45c..42989bf6d57 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java @@ -1,10 +1,18 @@ package org.egov.project.service; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.ds.Tuple; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskBulkRequest; import org.egov.common.models.project.TaskRequest; @@ -17,8 +25,10 @@ import org.egov.project.repository.ProjectRepository; import org.egov.project.repository.ProjectTaskRepository; import org.egov.project.service.enrichment.ProjectTaskEnrichmentService; +import org.egov.project.validator.task.PtExistentEntityValidator; import org.egov.project.validator.task.PtIsDeletedSubEntityValidator; import org.egov.project.validator.task.PtIsDeletedValidator; +import org.egov.project.validator.task.PtIsResouceEmptyValidator; import org.egov.project.validator.task.PtNonExistentEntityValidator; import org.egov.project.validator.task.PtNullIdValidator; import org.egov.project.validator.task.PtProductVariantIdValidator; @@ -31,12 +41,6 @@ import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdMethod; import static org.egov.common.utils.CommonUtils.handleErrors; @@ -66,14 +70,19 @@ public class ProjectTaskService { private final ProjectConfiguration projectConfiguration; private final ProjectTaskEnrichmentService enrichmentService; - + // || validator.getClass().equals(PtResourceQuantityValidator.class) FIXME add this back once requirement confirmation is done private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(PtProjectIdValidator.class) + || validator.getClass().equals(PtExistentEntityValidator.class) + || validator.getClass().equals(PtIsResouceEmptyValidator.class) + || validator.getClass().equals(PtProjectBeneficiaryIdValidator.class) || validator.getClass().equals(PtProductVariantIdValidator.class); + // || validator.getClass().equals(PtResourceQuantityValidator.class) FIXME add this back once requirement confirmation is done private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(PtProjectIdValidator.class) + || validator.getClass().equals(PtIsResouceEmptyValidator.class) || validator.getClass().equals(PtProjectBeneficiaryIdValidator.class) || validator.getClass().equals(PtProductVariantIdValidator.class) || validator.getClass().equals(PtNullIdValidator.class) @@ -128,7 +137,7 @@ public List create(TaskBulkRequest request, boolean isBulk) { log.info("successfully created project tasks"); } } catch (Exception exception) { - log.error("error occurred while creating project tasks: {}", exception.getMessage()); + log.error("error occurred while creating project tasks: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validTasks, exception, SET_TASKS); } @@ -160,7 +169,7 @@ public List update(TaskBulkRequest request, boolean isBulk) { log.info("successfully updated bulk project tasks"); } } catch (Exception exception) { - log.error("error occurred while updating project tasks", exception); + log.error("error occurred while updating project tasks", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validTasks, exception, SET_TASKS); } @@ -190,7 +199,7 @@ public List delete(TaskBulkRequest request, boolean isBulk) { projectTaskRepository.save(validTasks, projectConfiguration.getDeleteProjectTaskTopic()); } } catch (Exception exception) { - log.error("error occurred while deleting entities: {}", exception); + log.error("error occurred while deleting entities: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validTasks, exception, SET_TASKS); } @@ -213,8 +222,8 @@ private Tuple, Map> validate(List(validTasks, errorDetailsMap); } - public List search(TaskSearch taskSearch, Integer limit, Integer offset, String tenantId, - Long lastChangedSince, Boolean includeDeleted) { + public SearchResponse search(TaskSearch taskSearch, Integer limit, Integer offset, String tenantId, + Long lastChangedSince, Boolean includeDeleted) { log.info("received request to search project task"); @@ -225,12 +234,13 @@ public List search(TaskSearch taskSearch, Integer limit, Integer offset, S .singletonList(taskSearch)), taskSearch); log.info("fetching project tasks with ids: {}", ids); - return projectTaskRepository.findById(ids, - idFieldName, includeDeleted).stream() + SearchResponse searchResponse = projectTaskRepository.findById(ids, + idFieldName, includeDeleted); + return SearchResponse.builder().response(searchResponse.getResponse().stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) - .collect(Collectors.toList()); + .collect(Collectors.toList())).totalCount(searchResponse.getTotalCount()).build(); } try { @@ -238,7 +248,7 @@ public List search(TaskSearch taskSearch, Integer limit, Integer offset, S return projectTaskRepository.find(taskSearch, limit, offset, tenantId, lastChangedSince, includeDeleted); } catch (QueryBuilderException e) { - log.error("error in building query", e); + log.error("error in building query", ExceptionUtils.getStackTrace(e)); throw new CustomException("ERROR_IN_QUERY", e.getMessage()); } } diff --git a/health-services/project/src/main/java/org/egov/project/service/UserActionService.java b/health-services/project/src/main/java/org/egov/project/service/UserActionService.java new file mode 100644 index 00000000000..0e0f76dec0e --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/service/UserActionService.java @@ -0,0 +1,213 @@ +package org.egov.project.service; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.ds.Tuple; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.models.project.useraction.UserActionSearch; +import org.egov.common.models.project.useraction.UserActionSearchRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.common.validator.Validator; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.repository.UserActionRepository; +import org.egov.project.service.enrichment.UserActionEnrichmentService; +import org.egov.project.validator.useraction.UaBoundaryValidator; +import org.egov.project.validator.useraction.UaExistentEntityValidator; +import org.egov.project.validator.useraction.UaNonExistentEntityValidator; +import org.egov.project.validator.useraction.UaNullIdValidator; +import org.egov.project.validator.useraction.UaProjectIdValidator; +import org.egov.project.validator.useraction.UaRowVersionValidator; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.project.Constants.SET_USER_ACTION; +import static org.egov.project.Constants.VALIDATION_ERROR; + +@Service +@Slf4j +public class UserActionService { + private final IdGenService idGenService; // Service for generating unique IDs + private final UserActionRepository userActionTaskRepository; // Repository for user actions + private final ServiceRequestClient serviceRequestClient; // Client for external service requests + private final ProjectConfiguration projectConfiguration; // Configuration properties for the project + private final UserActionEnrichmentService userActionEnrichmentService; // Service for enriching user actions + private final List> validators; // List of validators for user actions + + // Predicate to filter validators applicable for creation + private final Predicate> isApplicableForCreate = validator -> + validator.getClass().equals(UaProjectIdValidator.class) + || validator.getClass().equals(UaExistentEntityValidator.class) + || validator.getClass().equals(UaBoundaryValidator.class); + + // Predicate to filter validators applicable for updates + private final Predicate> isApplicableForUpdate = validator -> + validator.getClass().equals(UaProjectIdValidator.class) + || validator.getClass().equals(UaNullIdValidator.class) + || validator.getClass().equals(UaNonExistentEntityValidator.class) + || validator.getClass().equals(UaRowVersionValidator.class) + || validator.getClass().equals(UaBoundaryValidator.class); + + // Constructor for dependency injection + @Autowired + public UserActionService( + IdGenService idGenService, + UserActionRepository userActionTaskRepository, + ServiceRequestClient serviceRequestClient, + ProjectConfiguration projectConfiguration, + UserActionEnrichmentService userActionEnrichmentService, + List> validators + ) { + this.idGenService = idGenService; + this.userActionTaskRepository = userActionTaskRepository; + this.serviceRequestClient = serviceRequestClient; + this.projectConfiguration = projectConfiguration; + this.userActionEnrichmentService = userActionEnrichmentService; + this.validators = validators; + } + + // Method to handle the creation of user actions + public List create(UserActionBulkRequest request, boolean isBulk) { + log.info("Received request to create bulk closed household userActions"); + + // Validate the request and get valid user actions along with error details + Tuple, Map> tuple = validate(validators, isApplicableForCreate, request, isBulk); + Map errorDetailsMap = tuple.getY(); + List validUserActions = tuple.getX(); + + try { + // If there are valid user actions, enrich and save them + if (!validUserActions.isEmpty()) { + log.info("Processing {} valid entities", validUserActions.size()); + userActionEnrichmentService.create(validUserActions, request); + userActionTaskRepository.save(validUserActions, projectConfiguration.getCreateUserActionTopic()); + log.info("Successfully created closed household userActions"); + } + } catch (Exception exception) { + // Handle and log any exceptions that occur + log.error("Error occurred while creating closed household userActions: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validUserActions, exception, SET_USER_ACTION); + } + + // Handle any validation errors + handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); + + return validUserActions; + } + + // Method to handle the update of user actions + public List update(UserActionBulkRequest request, boolean isBulk) { + log.info("Received request to update bulk closed household userActions"); + + // Validate the request and get valid user actions along with error details + Tuple, Map> tuple = validate(validators, isApplicableForUpdate, request, isBulk); + Map errorDetailsMap = tuple.getY(); + List validUserActions = tuple.getX(); + + try { + // If there are valid user actions, enrich and update them + if (!validUserActions.isEmpty()) { + log.info("Processing {} valid entities", validUserActions.size()); + userActionEnrichmentService.update(validUserActions, request); + userActionTaskRepository.save(validUserActions, projectConfiguration.getUpdateUserActionTopic()); + log.info("Successfully updated bulk closed household userActions"); + } + } catch (Exception exception) { + // Handle and log any exceptions that occur + log.error("Error occurred while updating closed household userActions: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validUserActions, exception, SET_USER_ACTION); + } + + // Handle any validation errors + handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); + + return validUserActions; + } + + // Method to validate user action requests + private Tuple, Map> validate(List> validators, + Predicate> applicableValidators, + UserActionBulkRequest request, boolean isBulk) { + log.info("Validating request"); + + // Validate the request using the applicable validators + Map errorDetailsMap = CommonUtils.validate(validators, + applicableValidators, request, + SET_USER_ACTION); + + // Throw exception if there are validation errors and it's not a bulk request + if (!errorDetailsMap.isEmpty() && !isBulk) { + throw new CustomException(VALIDATION_ERROR, errorDetailsMap.values().toString()); + } + + // Filter and return valid user actions + List validUserActions = request.getUserActions().stream() + .filter(notHavingErrors()).collect(Collectors.toList()); + return new Tuple<>(validUserActions, errorDetailsMap); + } + + // Method to search for user actions based on the request and URL parameters + public SearchResponse search(UserActionSearchRequest request, URLParams urlParams) { + log.info("Received request to search project UserAction"); + + UserActionSearch userActionSearch = request.getUserAction(); + + // Determine the ID field name for search + String idFieldName = getIdFieldName(userActionSearch); + if (isSearchByIdOnly(userActionSearch, idFieldName)) { + log.info("Searching project UserAction by id"); + + // Retrieve IDs and search for user actions by ID + List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections + .singletonList(userActionSearch)), + userActionSearch); + log.info("Fetching closed household userActions with ids: {}", ids); + SearchResponse searchResponse = userActionTaskRepository.findById(ids, idFieldName); + return SearchResponse.builder().response(searchResponse.getResponse().stream() + .filter(lastChangedSince(urlParams.getLastChangedSince())) + .filter(havingTenantId(urlParams.getTenantId())) + .filter(includeDeleted(urlParams.getIncludeDeleted())) + .collect(Collectors.toList())).totalCount(searchResponse.getTotalCount()).build(); + } + + try { + // Search using the criteria specified in the request + log.info("Searching project user actions using criteria"); + return userActionTaskRepository.find(userActionSearch, urlParams); + } catch (QueryBuilderException e) { + // Handle and log query building exceptions + log.error("Error in building query: {}", ExceptionUtils.getStackTrace(e)); + throw new CustomException("ERROR_IN_QUERY", e.getMessage()); + } + } + + // Method to put user actions into cache + public void putInCache(List userActions) { + log.info("Putting {} closed household userActions in cache", userActions.size()); + userActionTaskRepository.putInCache(userActions); + log.info("Successfully put closed household userActions in cache"); + } +} diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectBeneficiaryEnrichmentService.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectBeneficiaryEnrichmentService.java index 703a2791b7f..880fef8d268 100644 --- a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectBeneficiaryEnrichmentService.java +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectBeneficiaryEnrichmentService.java @@ -68,9 +68,9 @@ public void update(List validProjectBeneficiaries, List projectBeneficiaryIds = new ArrayList<>(projectBeneficiaryMap.keySet()); List existingProjectBeneficiaryIds = projectBeneficiaryRepository.findById( projectBeneficiaryIds, - false, - getIdFieldName(idMethod) - ); + getIdFieldName(idMethod), + false + ).getResponse(); log.info("updating Ids from existing entities"); enrichIdsFromExistingEntities(projectBeneficiaryMap, existingProjectBeneficiaryIds, idMethod); diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java index 182473417e0..2bd670f589f 100644 --- a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java @@ -1,15 +1,24 @@ package org.egov.project.service.enrichment; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import digit.models.coremodels.AuditDetails; +import java.util.Map; +import java.util.ArrayList; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.models.project.Document; import org.egov.common.models.project.Project; import org.egov.common.models.project.ProjectRequest; import org.egov.common.models.project.Target; +import org.egov.common.producer.Producer; import org.egov.common.service.IdGenService; import org.egov.project.config.ProjectConfiguration; +import org.egov.project.service.ProjectService; import org.egov.project.util.ProjectServiceUtil; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; @@ -29,6 +38,11 @@ public class ProjectEnrichment { @Autowired private ProjectServiceUtil projectServiceUtil; + @Autowired + private Producer producer; + @Autowired + private ProjectConfiguration projectConfiguration; + @Autowired private IdGenService idGenService; @@ -77,15 +91,8 @@ public void enrichProjectOnCreate(ProjectRequest request, List parentPr } /* Enrich Project on Update Request */ - public void enrichProjectOnUpdate(ProjectRequest request, List projectsFromDB) { + public void enrichProjectOnUpdate(ProjectRequest request, Project project , Project projectFromDB) { RequestInfo requestInfo = request.getRequestInfo(); - List projectsFromRequest = request.getProjects(); - - for (Project project : projectsFromRequest) { - String projectId = String.valueOf(project.getId()); - Project projectFromDB = projectsFromDB.stream().filter(p -> projectId.equals(String.valueOf(p.getId()))).findFirst().orElse(null); - - if (projectFromDB != null) { //Updating lastModifiedTime and lastModifiedBy for Project enrichProjectRequestOnUpdate(project, projectFromDB, requestInfo); log.info("Enriched project in update project request"); @@ -101,8 +108,6 @@ public void enrichProjectOnUpdate(ProjectRequest request, List projects //Add new document if id is empty or update lastModifiedTime and lastModifiedBy if id exists enrichProjectDocumentOnUpdate(project, projectFromDB, requestInfo); log.info("Enriched document in update project request"); - } - } } /* Enrich Project with id and audit details */ @@ -117,12 +122,174 @@ private void enrichProjectRequestOnCreate(Project projectRequest, RequestInfo re } /* Enrich Project update request with last modified by and last modified time */ - private void enrichProjectRequestOnUpdate(Project projectRequest, Project projectFromDB, RequestInfo requestInfo) { + public void enrichProjectRequestOnUpdate(Project projectRequest, Project projectFromDB, RequestInfo requestInfo) { projectRequest.setAuditDetails(projectFromDB.getAuditDetails()); AuditDetails auditDetails = projectServiceUtil.getAuditDetails(requestInfo.getUserInfo().getUuid(), projectFromDB.getAuditDetails(), false); projectRequest.setAuditDetails(auditDetails); log.info("Enriched project audit details for project " + projectRequest.getId()); } + public void enrichProjectCascadingDatesOnUpdate(Project project, Project projectFromDB) + { + // enrich project start and end dates along with ancestors and descendants + enrichProjectStartAndEndDateOfBothAncestorsAndDescendantsIfFoundAccordingly(project, + projectFromDB); + } + + private void enrichProjectStartAndEndDateOfBothAncestorsAndDescendantsIfFoundAccordingly( + Project projectRequest, Project projectFromDB) { + long startDate = projectRequest.getStartDate(); + long endDate = projectRequest.getEndDate(); + + /* + * Update both cycle dates and project start and end dates of descendants + */ + updateProjects(projectRequest, projectFromDB, startDate, endDate, true); + + /* + * Update both cycle dates and project start and end dates of ancestors in a way like start date = min(current, existing) + * and end date = max(current, existing) + */ + updateProjects(projectRequest, projectFromDB, startDate, endDate, false); + } + + + private void updateProjects(Project projectRequest, Project projectFromDB, long startDate, long endDate, boolean isDescendant) { + /* + * Get the list of projects from the database that are either descendants or ancestors + */ + List projectsFromDb = isDescendant ? projectFromDB.getDescendants() : projectFromDB.getAncestors(); + List modifiedProjectsFromDb = new ArrayList<>(); + + if (projectsFromDb != null) { + for (Project project : projectsFromDb) { + /* + * Update the project dates based on whether it is a descendant or ancestor + */ + updateProjectDates(project, startDate, endDate, isDescendant); + + /* + * Update the project cycles based on the request and whether it is a descendant or ancestor + */ + updateCycles(project, projectRequest, isDescendant); + + /* + * Add the modified project to the list + */ + modifiedProjectsFromDb.add(project); + } + + /* + * Push the modified projects to Kafka + */ + pushProjectsToKafka(modifiedProjectsFromDb); + } + } + + private void updateProjectDates(Project project, long startDate, long endDate, boolean isDescendant) { + if (isDescendant) { + /* + * For descendant projects, directly set the start and end dates + */ + project.setStartDate(startDate); + project.setEndDate(endDate); + } else { + /* + * For ancestor projects, set the start date to the minimum of the current and existing start dates, + * and set the end date to the maximum of the current and existing end dates + */ + project.setStartDate(Math.min(startDate, project.getStartDate())); + project.setEndDate(Math.max(endDate, project.getEndDate())); + } + } + + + private void updateCycles(Project descendantOrAncestor, Project projectRequest, boolean isDescendant) { + if (descendantOrAncestor.getAdditionalDetails() == null) { + return; + } + + ObjectMapper objectMapper = new ObjectMapper(); + + /* + * Extract additional details from descendant and request projects + */ + JsonNode descendantOrAncestorAdditionalDetails = objectMapper.valueToTree( + descendantOrAncestor.getAdditionalDetails()); + JsonNode descendantOrAncestorProjectTypeNode = descendantOrAncestorAdditionalDetails.get("projectType"); + + if (descendantOrAncestorProjectTypeNode != null) { + JsonNode descendantOrAncestorCyclesNode = descendantOrAncestorProjectTypeNode.get("cycles"); + + if (descendantOrAncestorCyclesNode != null && descendantOrAncestorCyclesNode.isArray()) { + /* + * Extract cycles from the request project + */ + JsonNode requestAdditionalDetails = objectMapper.valueToTree( + projectRequest.getAdditionalDetails()); + JsonNode requestProjectTypeNode = requestAdditionalDetails.get("projectType"); + + if (requestProjectTypeNode != null) { + JsonNode requestCyclesNode = requestProjectTypeNode.get("cycles"); + + if (requestCyclesNode != null && requestCyclesNode.isArray()) { + /* + * Iterate over descendant cycles and update as necessary + */ + for (JsonNode descendantOrAncestorCycleNode : descendantOrAncestorCyclesNode) { + String descendantOrAncestorCycleId = descendantOrAncestorCycleNode.get("id").asText(); + + for (JsonNode requestCycleNode : requestCyclesNode) { + String requestCycleId = requestCycleNode.get("id").asText(); + + if (descendantOrAncestorCycleId.equals(requestCycleId)) { + /* + * Update start and end dates of descendant cycle node + */ + long requestStartDate = requestCycleNode.get("startDate").asLong(); + long requestEndDate = requestCycleNode.get("endDate").asLong(); + long currentStartDate = descendantOrAncestorCycleNode.get("startDate").asLong(); + long currentEndDate = descendantOrAncestorCycleNode.get("endDate").asLong(); + if (isDescendant) { + ((ObjectNode) descendantOrAncestorCycleNode).put("startDate", requestStartDate); + ((ObjectNode) descendantOrAncestorCycleNode).put("endDate", requestEndDate); + } else { + ((ObjectNode) descendantOrAncestorCycleNode).put("startDate", + Math.min(requestStartDate, currentStartDate)); + ((ObjectNode) descendantOrAncestorCycleNode).put("endDate", + Math.max(requestEndDate, currentEndDate)); + } + break; // Once updated, exit the loop for this descendantCycleNode + } + } + } + + /* + * Convert updated additional details back to a map and set it on the descendant or ancestor project + */ + Map updatedAdditionalDetails = objectMapper.convertValue( + descendantOrAncestorAdditionalDetails, new TypeReference>() {}); + descendantOrAncestor.setAdditionalDetails(updatedAdditionalDetails); + } + } + } + } + } + + + private void pushProjectsToKafka(List projects) { + /* + * Create a ProjectRequest object with the list of projects + */ + ProjectRequest projectRequest = ProjectRequest.builder() + .projects(projects) + .build(); + + /* + * Push the ProjectRequest to the Kafka topic for updating projects + */ + producer.push(projectConfiguration.getUpdateProjectTopic(), projectRequest); + } + //Enrich Project with Parent Hierarchy. If parent Project hierarchy is not present then add parent locality at the beginning of project hierarchy, if present add Parent project's project hierarchy private void enrichProjectHierarchy(Project projectRequest, List parentProjects) { @@ -301,7 +468,7 @@ private List getIdList(RequestInfo requestInfo, String tenantId, String try { return idGenService.getIdList(requestInfo, tenantId, idKey, idformat, count); } catch (Exception exception) { - log.error("error while calling id gen service", exception); + log.error("error while calling id gen service", ExceptionUtils.getStackTrace(exception)); throw new CustomException("IDGEN_ERROR", String.format("error while calling id gen service for %s", idformat)); } diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java index c3b7564e49f..db974db9be9 100644 --- a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java @@ -1,5 +1,9 @@ package org.egov.project.service.enrichment; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import digit.models.coremodels.AuditDetails; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.project.Address; @@ -9,10 +13,7 @@ import org.egov.common.service.IdGenService; import org.egov.project.config.ProjectConfiguration; import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; +import org.springframework.util.CollectionUtils; import static org.egov.common.utils.CommonUtils.enrichForCreate; import static org.egov.common.utils.CommonUtils.enrichForUpdate; @@ -66,20 +67,24 @@ public void delete(List validTasks, TaskBulkRequest request) throws Except for (Task task : validTasks) { if (task.getIsDeleted()) { log.info("enriching all task resources for delete"); - for (TaskResource resource : task.getResources()) { - resource.setIsDeleted(true); - updateAuditDetailsForResource(request, resource); + if(!CollectionUtils.isEmpty(task.getResources())) { + for (TaskResource resource : task.getResources()) { + resource.setIsDeleted(true); + updateAuditDetailsForResource(request, resource); + } } updateAuditDetailsForTask(request, task); task.setRowVersion(task.getRowVersion() + 1); } else { int previousRowVersion = task.getRowVersion(); log.info("enriching task resources for delete"); - task.getResources().stream().filter(TaskResource::getIsDeleted).forEach(resource -> { - updateAuditDetailsForResource(request, resource); - updateAuditDetailsForTask(request, task); - task.setRowVersion(previousRowVersion + 1); - }); + if(!CollectionUtils.isEmpty(task.getResources())) { + task.getResources().stream().filter(TaskResource::getIsDeleted).forEach(resource -> { + updateAuditDetailsForResource(request, resource); + updateAuditDetailsForTask(request, task); + task.setRowVersion(previousRowVersion + 1); + }); + } } } log.info("enrichment done"); @@ -102,6 +107,7 @@ private static void updateAuditDetailsForResource(TaskBulkRequest request, TaskR private static void enrichResourcesForUpdate(TaskBulkRequest request, List tasks) { log.info("enriching resources"); for (Task task : tasks) { + if(CollectionUtils.isEmpty(task.getResources())) continue; List resourcesToCreate = task.getResources().stream() .filter(r -> r.getId() == null).collect(Collectors.toList()); List resourcesToUpdate = task.getResources().stream() @@ -143,6 +149,8 @@ private static void enrichResourcesForCreate(TaskBulkRequest request, for (Task task : validTasks) { log.info("enriching resources"); List resources = task.getResources(); + if(CollectionUtils.isEmpty(resources)) + continue; enrichResourcesForCreate(request, resources, task.getId()); } } diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/UserActionEnrichmentService.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/UserActionEnrichmentService.java new file mode 100644 index 00000000000..afa331fc1cc --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/UserActionEnrichmentService.java @@ -0,0 +1,67 @@ +package org.egov.project.service.enrichment; + +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.repository.UserActionRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import static org.egov.common.utils.CommonUtils.enrichForCreate; +import static org.egov.common.utils.CommonUtils.enrichForUpdate; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.project.Constants.PROJECT_USER_ACTION_ENRICHMENT_ERROR; + +@Service +@Slf4j +public class UserActionEnrichmentService { + private final IdGenService idGenService; + + private final ProjectConfiguration projectConfiguration; + + private final UserActionRepository userActionRepository; + + @Autowired + public UserActionEnrichmentService( + IdGenService idGenService, + ProjectConfiguration projectConfiguration, + UserActionRepository userActionRepository + ) { + this.idGenService = idGenService; + this.projectConfiguration = projectConfiguration; + this.userActionRepository = userActionRepository; + } + + public void create(List entities, UserActionBulkRequest request) { + log.info("starting the enrichment for create UserActions"); + log.info("generating IDs using UUID"); + try { + List idList = CommonUtils.uuidSupplier().apply(entities.size()); + log.info("enriching UserActions with generated IDs"); + enrichForCreate(entities, idList, request.getRequestInfo(),false); + log.info("enrichment done"); + } catch (Exception exception) { + log.error("Error during enrichment for create UserActions", exception); + throw new CustomException(PROJECT_USER_ACTION_ENRICHMENT_ERROR, "Error during enrichment for create UserActions" + exception); + } + } + + public void update(List entities, UserActionBulkRequest request) { + log.info("starting the enrichment for update UserActions"); + try { + Map userActionMap = getIdToObjMap(entities); + enrichForUpdate(userActionMap, entities, request); + log.info("enrichment done"); + } catch (Exception exception) { + log.error("Error during enrichment for update UserActions", exception); + throw new CustomException(PROJECT_USER_ACTION_ENRICHMENT_ERROR, "Error during enrichment for update UserActions" + exception); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java b/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java index 2894a5aa5d6..3a0a08d31ea 100644 --- a/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java +++ b/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java @@ -6,6 +6,7 @@ import lombok.extern.slf4j.Slf4j; import net.minidev.json.JSONObject; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.tracer.model.CustomException; @@ -64,7 +65,7 @@ public void validateBoundaryDetails(Map> locations, String response = Optional.ofNullable(serviceRequestRepository.fetchResult(uri, RequestInfoWrapper.builder().requestInfo(requestInfo).build(), LinkedHashMap.class)); } catch (Exception e) { - log.error("error while calling boundary service", e); + log.error("error while calling boundary service", ExceptionUtils.getStackTrace(e)); throw new CustomException("BOUNDARY_ERROR", "error while calling boundary service"); } @@ -91,4 +92,4 @@ public void validateBoundaryDetails(Map> locations, String } } -} +} \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/util/BoundaryV2Util.java b/health-services/project/src/main/java/org/egov/project/util/BoundaryV2Util.java new file mode 100644 index 00000000000..0face50eb9e --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/util/BoundaryV2Util.java @@ -0,0 +1,84 @@ +package org.egov.project.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.core.Boundary; +import org.egov.project.web.models.boundary.BoundaryResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +/** + * Utility class to validate boundary details. + */ +@Component +@Slf4j +public class BoundaryV2Util { + + // Injecting boundary host value from configuration + @Value("${egov.boundary.host}") + private String boundaryHost; + + // Injecting boundary search URL value from configuration + @Value("${egov.boundary.search.url}") + private String boundarySearchUrl; + + @Autowired + private ServiceRequestClient serviceRequestClient; + + /** + * Validates boundary details against the egov-location service response. + * + * @param boundaryTypeBoundariesMap A map of boundary types with lists of boundary codes + * @param tenantId The tenant ID + * @param requestInfo Request information + * @param hierarchyTypeCode Hierarchy type code + */ + public void validateBoundaryDetails(Map> boundaryTypeBoundariesMap, String tenantId, + RequestInfo requestInfo, String hierarchyTypeCode) { + // Flatten the lists of boundary codes from the map values + List boundaries = boundaryTypeBoundariesMap.values().stream().flatMap(List::stream) + .collect(Collectors.toList()); + if(CollectionUtils.isEmpty(boundaries)) return; + try { + // Fetch boundary details from the service + log.debug("Fetching boundary details for tenantId: {}, boundaries: {}", tenantId, boundaries); + BoundaryResponse boundarySearchResponse = serviceRequestClient.fetchResult( + new StringBuilder(boundaryHost + + boundarySearchUrl + + "?limit=" + boundaries.size() + + "&offset=0&tenantId=" + tenantId + + "&codes=" + String.join(",", boundaries)), + requestInfo, + BoundaryResponse.class + ); + log.debug("Boundary details fetched successfully for tenantId: {}", tenantId); + + // Extract invalid boundary codes + List invalidBoundaryCodes = new ArrayList<>(boundaries); + invalidBoundaryCodes.removeAll(boundarySearchResponse.getBoundary().stream() + .map(Boundary::getCode) + .collect(Collectors.toList()) + ); + + // Throw exception if invalid boundary codes are found + if (!invalidBoundaryCodes.isEmpty()) { + log.error("The boundary data for the codes {} is not available.", invalidBoundaryCodes); + throw new CustomException("INVALID_BOUNDARY_DATA", "The boundary data for the code " + + invalidBoundaryCodes + " is not available"); + } + } catch (Exception e) { + log.error("Exception while searching boundaries for tenantId: {}", tenantId, e); + // Throw a custom exception if an error occurs during boundary search + throw new CustomException("BOUNDARY_SERVICE_SEARCH_ERROR","Error in while fetching boundaries from Boundary Service : " + e.getMessage()); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java b/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java index 950985ac246..4de61e5ab79 100644 --- a/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java +++ b/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java @@ -1,10 +1,16 @@ package org.egov.project.util; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; + import digit.models.coremodels.mdms.MasterDetail; import digit.models.coremodels.mdms.MdmsCriteria; import digit.models.coremodels.mdms.MdmsCriteriaReq; import digit.models.coremodels.mdms.ModuleDetail; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.project.Project; @@ -14,16 +20,13 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; - +import static org.egov.project.util.ProjectConstants.MASTER_ATTENDANCE_SESSION; import static org.egov.project.util.ProjectConstants.MASTER_DEPARTMENT; import static org.egov.project.util.ProjectConstants.MASTER_NATUREOFWORK; import static org.egov.project.util.ProjectConstants.MASTER_PROJECTTYPE; import static org.egov.project.util.ProjectConstants.MASTER_TENANTS; import static org.egov.project.util.ProjectConstants.MDMS_COMMON_MASTERS_MODULE_NAME; +import static org.egov.project.util.ProjectConstants.MDMS_HCM_ATTENDANCE_MODULE_NAME; import static org.egov.project.util.ProjectConstants.MDMS_TENANT_MODULE_NAME; @Component @@ -47,7 +50,7 @@ public Object mDMSCall(ProjectRequest request, String tenantId) { try { result = serviceRequestRepository.fetchResult(getMdmsSearchUrl(), mdmsCriteriaReq, LinkedHashMap.class); } catch (Exception e) { - log.error("error while calling mdms", e); + log.error("error while calling mdms", ExceptionUtils.getStackTrace(e)); throw new CustomException("MDMS_ERROR", "error while calling mdms"); } return result; @@ -58,11 +61,13 @@ public MdmsCriteriaReq getMDMSRequest(RequestInfo requestInfo, String tenantId, ModuleDetail projectMDMSModuleDetail = getMDMSModuleRequestData(request); ModuleDetail projectDepartmentModuleDetail = getDepartmentModuleRequestData(request); ModuleDetail projectTenantModuleDetail = getTenantModuleRequestData(request); + ModuleDetail attendanceModuleDetail = getAttendanceModuleRequestData(request); List moduleDetails = new LinkedList<>(); moduleDetails.add(projectMDMSModuleDetail); moduleDetails.add(projectDepartmentModuleDetail); moduleDetails.add(projectTenantModuleDetail); + moduleDetails.add(attendanceModuleDetail); MdmsCriteria mdmsCriteria = MdmsCriteria.builder().moduleDetails(moduleDetails).tenantId(tenantId) .build(); @@ -123,4 +128,19 @@ private ModuleDetail getTenantModuleRequestData(ProjectRequest request) { return tenantModuleDetail; } -} + private ModuleDetail getAttendanceModuleRequestData(ProjectRequest request) { + List attendanceMasterDetails = new ArrayList<>(); + + MasterDetail attendanceSessionsMasterDetails = MasterDetail.builder().name(MASTER_ATTENDANCE_SESSION) + .filter(filterCode) + .build(); + + attendanceMasterDetails.add(attendanceSessionsMasterDetails); + + ModuleDetail attendanceModuleDetail = ModuleDetail.builder().masterDetails(attendanceMasterDetails) + .moduleName(MDMS_HCM_ATTENDANCE_MODULE_NAME).build(); + + return attendanceModuleDetail; + } + +} \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java b/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java index 5d0240ba7e7..0252281f736 100644 --- a/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java +++ b/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java @@ -1,16 +1,29 @@ package org.egov.project.util; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import org.egov.common.models.project.TaskStatus; + public class ProjectConstants { public static final String MASTER_TENANTS = "tenants"; public static final String MDMS_TENANT_MODULE_NAME = "tenant"; public static final String MDMS_COMMON_MASTERS_MODULE_NAME = "common-masters"; + public static final String MDMS_HCM_ATTENDANCE_MODULE_NAME = "HCM-ATTENDANCE"; public static final String MASTER_DEPARTMENT = "Department"; public static final String MASTER_PROJECTTYPE = "ProjectType"; //location public static final String MASTER_NATUREOFWORK = "NatureOfWork"; + public static final String MASTER_ATTENDANCE_SESSION = "AttendanceSessions"; public static final String CODE = "code"; //General public static final String SEMICOLON = ":"; public static final String DOT = "."; public static final String PROJECT_PARENT_HIERARCHY_SEPERATOR = "."; -} + public static final String TASK_NOT_ALLOWED = "TASK_NOT_ALLOWED"; + public static final String TASK_NOT_ALLOWED_BENEFICIARY_REFUSED_RESOURCE_EMPTY_ERROR_MESSAGE = "Task not allowed as resources can not be provided when " + TaskStatus.BENEFICIARY_REFUSED; + public static final String TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE = "Task not allowed as resources can not be empty when "; + public static final String NUMBER_OF_SESSIONS = "numberOfSessions"; + public static final String OR = " OR "; + + +} \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java b/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java index 90b2c3cfe12..7d750e8d984 100644 --- a/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java +++ b/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java @@ -1,10 +1,23 @@ package org.egov.project.util; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import digit.models.coremodels.AuditDetails; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import org.egov.common.models.project.Project; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import static java.util.Objects.isNull; @Component public class ProjectServiceUtil { + @Autowired + private ObjectMapper objectMapper; public AuditDetails getAuditDetails(String by, AuditDetails auditDetails, Boolean isCreate) { Long time = System.currentTimeMillis(); @@ -14,4 +27,53 @@ public AuditDetails getAuditDetails(String by, AuditDetails auditDetails, Boolea return AuditDetails.builder().createdBy(auditDetails.getCreatedBy()).lastModifiedBy(by) .createdTime(auditDetails.getCreatedTime()).lastModifiedTime(time).build(); } + + + /** + * Creates a map from a list of projects, using project IDs as keys. + * + * @param projects The list of projects to be converted into a map. + * @return A map with project IDs as keys and project objects as values. + */ + public Map createProjectMap(List projects) { + return projects.stream() + .collect(Collectors.toMap(p -> String.valueOf(p.getId()), Function.identity())); + } + + public void mergeAdditionalDetails( Project project , Project projectFromDb) { + project.setAdditionalDetails(jsonMerge( objectMapper.valueToTree(projectFromDb.getAdditionalDetails()), + objectMapper.valueToTree(project.getAdditionalDetails()))); + } + /** + * Method to merge additional details during update + * + * @param mainNode + * @param updateNode + * @return + */ + public JsonNode jsonMerge(JsonNode mainNode, JsonNode updateNode) { + + if (isNull(mainNode) || mainNode.isNull()) + return updateNode; + if (isNull(updateNode) || updateNode.isNull()) + return mainNode; + + Iterator fieldNames = updateNode.fieldNames(); + while (fieldNames.hasNext()) { + String fieldName = fieldNames.next(); + JsonNode jsonNode = mainNode.get(fieldName); + // if field exists and is an embedded object + if (jsonNode != null && jsonNode.isObject()) { + jsonMerge(jsonNode, updateNode.get(fieldName)); + } else { + if (mainNode instanceof ObjectNode) { + // Overwrite field + JsonNode value = updateNode.get(fieldName); + ((ObjectNode) mainNode).set(fieldName, value); + } + } + + } + return mainNode; + } } diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/BeneficiaryValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/BeneficiaryValidator.java index 756f7875883..19c8454d63a 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/BeneficiaryValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/BeneficiaryValidator.java @@ -8,6 +8,7 @@ import digit.models.coremodels.mdms.MdmsCriteriaReq; import digit.models.coremodels.mdms.ModuleDetail; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; @@ -188,7 +189,7 @@ private void searchHouseholdBeneficiary( } } } catch (Exception e) { - log.error("error while fetching households list", e); + log.error("error while fetching households list", ExceptionUtils.getStackTrace(e)); beneficiaryList.forEach(b -> { Error error = getErrorForEntityWithNetworkError(); populateErrorDetails(b, error, errorDetailsMap); diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbExistentEntityValidator.java new file mode 100644 index 00000000000..97acdc3d867 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbExistentEntityValidator.java @@ -0,0 +1,103 @@ +package org.egov.project.validator.beneficiary; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.BeneficiaryBulkRequest; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.models.project.ProjectBeneficiarySearch; +import org.egov.common.validator.Validator; +import org.egov.project.repository.ProjectBeneficiaryRepository; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of ProjectBeneficiary entities with the given client reference IDs. + * This validator checks if the provided ProjectBeneficiary entities already exist in the database based on their client reference IDs. + * + * The validation ensures that each ProjectBeneficiary entity in the bulk request has a unique client reference ID, + * and if an entity with the same client reference ID already exists, an error is recorded. + * + * @author kanishq-egov + */ +@Component +@Order(value = 1) +@Slf4j +public class PbExistentEntityValidator implements Validator { + + private final ProjectBeneficiaryRepository projectBeneficiaryRepository; + + /** + * Constructor to initialize the ProjectBeneficiaryRepository dependency. + * + * @param projectBeneficiaryRepository The repository for ProjectBeneficiary entities. + * It is used to query the database to check if entities with given client reference IDs exist. + */ + public PbExistentEntityValidator(ProjectBeneficiaryRepository projectBeneficiaryRepository) { + this.projectBeneficiaryRepository = projectBeneficiaryRepository; + } + + /** + * Validates the existence of ProjectBeneficiary entities with the given client reference IDs. + * + * This method checks if any of the ProjectBeneficiary entities in the provided bulk request already exist in the database. + * If an entity with a client reference ID already exists, an error is added to the map with the entity. + * + * @param request The bulk request containing ProjectBeneficiary entities to be validated. + * @return A map where the key is a ProjectBeneficiary entity and the value is a list of associated Error details. + * The map contains entries only for entities that have errors (i.e., those whose client reference IDs already exist in the database). + */ + @Override + public Map> validate(BeneficiaryBulkRequest request) { + // Initialize a map to hold ProjectBeneficiary entities and their associated error details. + Map> errorDetailsMap = new HashMap<>(); + + // Extract the list of ProjectBeneficiary entities from the request. + List entities = request.getProjectBeneficiaries(); + + // Extract the client reference IDs from ProjectBeneficiary entities that do not have existing errors. + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) // Filter out entities that already have errors. + .map(ProjectBeneficiary::getClientReferenceId) // Map to extract client reference IDs. + .collect(Collectors.toList()); // Collect the IDs into a list. + + // Create a map of client reference ID to ProjectBeneficiary entity for quick lookup. + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty. + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map. + + // Create a search object to query entities by client reference IDs. + ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search. + .build(); + + // Check if the client reference ID list is not empty before querying the database. + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing entities with the given client reference IDs. + List existingClientReferenceIds = + projectBeneficiaryRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, populate error details for the corresponding ProjectBeneficiary entity. + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation. + Error error = getErrorForUniqueEntity(); + // Populate error details for the individual entity associated with the client reference ID. + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); + }); + } + + // Return the map containing ProjectBeneficiary entities and their associated error details. + return errorDetailsMap; + } + +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbNonExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbNonExistentEntityValidator.java index 4f4c4e72cb1..01944744fba 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbNonExistentEntityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbNonExistentEntityValidator.java @@ -1,24 +1,25 @@ package org.egov.project.validator.beneficiary; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; import org.egov.common.models.project.BeneficiaryBulkRequest; import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.models.project.ProjectBeneficiarySearch; import org.egov.common.validator.Validator; import org.egov.project.repository.ProjectBeneficiaryRepository; +import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdToObjMap; import static org.egov.common.utils.CommonUtils.getMethod; import static org.egov.common.utils.CommonUtils.getObjClass; @@ -49,10 +50,31 @@ public Map> validate(BeneficiaryBulkRequest requ Method idMethod = getMethod(GET_ID, objClass); Map iMap = getIdToObjMap(projectBeneficiaries .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + // Lists to store IDs and client reference IDs + List idList = new ArrayList<>(); + List clientReferenceIdList = new ArrayList<>(); + // Extract IDs and client reference IDs from Project Beneficiary entities + projectBeneficiaries.forEach(entity -> { + idList.add(entity.getId()); + clientReferenceIdList.add(entity.getClientReferenceId()); + }); if (!iMap.isEmpty()) { - List beneficiaryIds = new ArrayList<>(iMap.keySet()); - List existingProjectBeneficiaries = projectBeneficiaryRepository - .findById(beneficiaryIds, false, getIdFieldName(idMethod)); + ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() + .clientReferenceId(clientReferenceIdList) + .id(idList) + .build(); + + List existingProjectBeneficiaries; + try { + // Query the repository to find existing entities + existingProjectBeneficiaries = projectBeneficiaryRepository.find(projectBeneficiarySearch, projectBeneficiaries.size(), 0, + projectBeneficiaries.get(0).getTenantId(), null, false).getResponse(); + } catch (Exception e) { + // Handle query builder exception + log.error("Search failed for ProjectBeneficiary with error: {}", e.getMessage(), e); + throw new CustomException("PROJECT_BENEFICIARY_SEARCH_FAILED", "Search Failed for ProjectBeneficiary, " + e.getMessage()); + } + List nonExistentIndividuals = checkNonExistentEntities(iMap, existingProjectBeneficiaries, idMethod); nonExistentIndividuals.forEach(projectBeneficiary -> { diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbRowVersionValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbRowVersionValidator.java index d6de91c5439..a36e39664a6 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbRowVersionValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbRowVersionValidator.java @@ -49,7 +49,7 @@ public Map> validate(BeneficiaryBulkRequest requ if (!iMap.isEmpty()) { List individualIds = new ArrayList<>(iMap.keySet()); List existingProjectBeneficiaries = projectBeneficiaryRepository.findById(individualIds, - false, getIdFieldName(idMethod)); + getIdFieldName(idMethod), false).getResponse(); List entitiesWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(iMap, existingProjectBeneficiaries, idMethod); entitiesWithMismatchedRowVersion.forEach(projectBeneficiary -> { diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbUniqueEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbUniqueEntityValidator.java index 13485596684..7feed061ea6 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbUniqueEntityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbUniqueEntityValidator.java @@ -8,6 +8,7 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -18,24 +19,42 @@ import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; +/** + * This class, PbUniqueEntityValidator, is a Spring component that serves as a validator for ensuring the uniqueness + * of entities (ProjectBeneficiaries) within a BeneficiaryBulkRequest. It implements the Validator interface, which + * allows it to validate the request by checking for duplicate entities based on their IDs. + */ @Component @Order(value = 2) @Slf4j public class PbUniqueEntityValidator implements Validator { + /** + * This method validates the uniqueness of entities within a BeneficiaryBulkRequest. + * + * @param request The BeneficiaryBulkRequest to validate. + * @return A map containing error details for entities that are not unique. + */ @Override public Map> validate(BeneficiaryBulkRequest request) { log.info("validating unique entity"); Map> errorDetailsMap = new HashMap<>(); List validProjectBeneficiaries = request.getProjectBeneficiaries() .stream().filter(notHavingErrors()).collect(Collectors.toList()); + if (!validProjectBeneficiaries.isEmpty()) { + + List duplicates = new ArrayList<>(); Map iMap = getIdToObjMap(validProjectBeneficiaries); + if (iMap.keySet().size() != validProjectBeneficiaries.size()) { - List duplicates = iMap.keySet().stream().filter(id -> + // Find duplicate entities by comparing their IDs + duplicates = iMap.keySet().stream().filter(id -> validProjectBeneficiaries.stream() .filter(projectBeneficiary -> projectBeneficiary.getId().equals(id)).count() > 1 ).collect(Collectors.toList()); + + // Populate error details for duplicate entities for (String key : duplicates) { Error error = getErrorForUniqueEntity(); populateErrorDetails(iMap.get(key), error, errorDetailsMap); @@ -44,4 +63,6 @@ public Map> validate(BeneficiaryBulkRequest requ } return errorDetailsMap; } + + } diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbUniqueTagsValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbUniqueTagsValidator.java new file mode 100644 index 00000000000..47800b3af65 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbUniqueTagsValidator.java @@ -0,0 +1,47 @@ +package org.egov.project.validator.beneficiary; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.BeneficiaryBulkRequest; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.project.validator.beneficiary.ValidatorUtils.validateUniqueTags; + +/** + * This class, PbUniqueEntityValidator, is a Spring component that serves as a validator for ensuring the uniqueness + * of entities (ProjectBeneficiaries) within a BeneficiaryBulkRequest. It implements the Validator interface, which + * allows it to validate the request by checking for duplicate entities based on their Voucher Tags. + */ +@Component +@Order(value = 2) +@Slf4j +public class PbUniqueTagsValidator implements Validator { + + /** + * This method validates the uniqueness of entities within a BeneficiaryBulkRequest. + * + * @param request The BeneficiaryBulkRequest to validate. + * @return A map containing error details for entities that are not unique. + */ + @Override + public Map> validate(BeneficiaryBulkRequest request) { + log.info("validating unique voucher tags"); + Map> errorDetailsMap = new HashMap<>(); + List validProjectBeneficiaries = request.getProjectBeneficiaries() + .stream().filter(notHavingErrors()).collect(Collectors.toList()); + + if (!validProjectBeneficiaries.isEmpty()) { + validateUniqueTags(validProjectBeneficiaries, errorDetailsMap); + } + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForCreateValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForCreateValidator.java new file mode 100644 index 00000000000..7140c580507 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForCreateValidator.java @@ -0,0 +1,118 @@ +package org.egov.project.validator.beneficiary; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.BeneficiaryBulkRequest; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.validator.Validator; +import org.egov.project.repository.ProjectBeneficiaryRepository; +import org.egov.common.models.project.ProjectBeneficiarySearch; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * This class, PbVoucherTagUniqueValidator, is a Spring component that serves as a validator for ensuring the uniqueness + * of voucher tags within a list of project beneficiaries. It implements the Validator interface, which allows it to + * validate a BeneficiaryBulkRequest containing a list of ProjectBeneficiary objects. Any duplicate voucher tags within + * the list result in error details being populated for the respective ProjectBeneficiary objects. + */ +@Component +@Order(value = 2) +@Slf4j +public class PbVoucherTagUniqueForCreateValidator implements Validator { + final ProjectBeneficiaryRepository projectBeneficiaryRepository; + + @Autowired + public PbVoucherTagUniqueForCreateValidator(ProjectBeneficiaryRepository projectBeneficiaryRepository) { + this.projectBeneficiaryRepository = projectBeneficiaryRepository; + } + + /** + * + * @param beneficiaryBulkRequest + * @return + */ + @Override + public Map> validate(BeneficiaryBulkRequest beneficiaryBulkRequest) { + log.info("validating unique tag for create"); + + // Create a map to store error details for each ProjectBeneficiary + Map> errorDetailsMap = new HashMap<>(); + + // Filter valid project beneficiaries (those without errors) + List validProjectBeneficiaries = beneficiaryBulkRequest.getProjectBeneficiaries() + .stream().filter(notHavingErrors()).collect(Collectors.toList()); + + if(!validProjectBeneficiaries.isEmpty()) { + // Get a list of invalid voucher tags + List existingProjectBeneficiaries = getInvalidVoucherTags(validProjectBeneficiaries); + + // Validate and populate errors for invalid voucher tags + if(!existingProjectBeneficiaries.isEmpty()) + validateAndPopulateErrors(validProjectBeneficiaries, existingProjectBeneficiaries, errorDetailsMap); + } + + return errorDetailsMap; + } + + // Helper method to validate and populate errors + private void validateAndPopulateErrors(List validProjectBeneficiaries, List existingProjectBeneficiaries, Map> errorDetailsMap) { + List existingVoucherTags = existingProjectBeneficiaries.stream().map(ProjectBeneficiary::getTag).collect(Collectors.toList()); + // Filter project beneficiaries that are valid and have invalid voucher tags + List invalidEntities = validProjectBeneficiaries.stream().filter(notHavingErrors()) + .filter(entity -> existingVoucherTags.contains(entity.getTag())) + .collect(Collectors.toList()); + + // For each invalid entity, create an error and populate error details + invalidEntities.forEach(projectBeneficiary -> { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(projectBeneficiary, error, errorDetailsMap); + }); + } + + // Helper method to get invalid voucher tags + private List getInvalidVoucherTags(List validProjectBeneficiaries) { + // Extract voucher tags from valid project beneficiaries + List voucherTags = validProjectBeneficiaries.stream() + .filter(Objects::nonNull) + .map(ProjectBeneficiary::getTag) + .collect(Collectors.toList()); + + if(CollectionUtils.isEmpty(voucherTags)) + return new ArrayList<>(); + + // Create a list to store existing project beneficiary with voucher tag + List existingProjectBeneficiaries; + + // Build a search request to find existing voucher tags + ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder().tag(voucherTags).build(); + + try { + log.info("Fetching project beneficiary based on voucher tags"); + existingProjectBeneficiaries = projectBeneficiaryRepository.find( + projectBeneficiarySearch, + voucherTags.size(), 0, validProjectBeneficiaries.get(0).getTenantId(), null, false + ).getResponse(); + } catch (Exception e) { + log.error("Exception while fetching project beneficiary service : ", e); + throw new CustomException("PROJECT_BENEFICIARY_VOUCHER_TAG_SEARCH_FAILED","Error occurred while fetching project beneficiary based on voucher tags. "+e); + } + + // return existing project beneficiaries + return existingProjectBeneficiaries; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForUpdateValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForUpdateValidator.java new file mode 100644 index 00000000000..20c7084b680 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForUpdateValidator.java @@ -0,0 +1,175 @@ +package org.egov.project.validator.beneficiary; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.BeneficiaryBulkRequest; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.validator.Validator; +import org.egov.project.repository.ProjectBeneficiaryRepository; +import org.egov.common.models.project.ProjectBeneficiarySearch; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +/** + * @author kanishq-egov + * This class, PbVoucherTagUniqueValidator, is a Spring component that serves as a validator for ensuring the uniqueness + * of voucher tags within a list of project beneficiaries. It implements the Validator interface, which allows it to + * validate a BeneficiaryBulkRequest containing a list of ProjectBeneficiary objects. Any duplicate voucher tags within + * the list result in error details being populated for the respective ProjectBeneficiary objects. + */ +@Component +@Order(value = 2) +@Slf4j +public class PbVoucherTagUniqueForUpdateValidator implements Validator { + final ProjectBeneficiaryRepository projectBeneficiaryRepository; + + @Autowired + public PbVoucherTagUniqueForUpdateValidator(ProjectBeneficiaryRepository projectBeneficiaryRepository) { + this.projectBeneficiaryRepository = projectBeneficiaryRepository; + } + + /** + * + * @param beneficiaryBulkRequest + * @return + */ + @Override + public Map> validate(BeneficiaryBulkRequest beneficiaryBulkRequest) { + log.info("validating unique tag"); + + // Create a map to store error details for each ProjectBeneficiary + Map> errorDetailsMap = new HashMap<>(); + + // Filter valid project beneficiaries (those without errors) + List validProjectBeneficiaries = beneficiaryBulkRequest.getProjectBeneficiaries() + .stream().filter(notHavingErrors()).filter(projectBeneficiary -> projectBeneficiary.getTag() != null).collect(Collectors.toList()); + + if(!validProjectBeneficiaries.isEmpty()) { + // Get a list of existing ProjectBeneficiaries based on IDs + List existingProjectBeneficiaries = getExistingProjectBeneficiaries(validProjectBeneficiaries); + + // Validate and populate errors for invalid voucher tags + if(!CollectionUtils.isEmpty(existingProjectBeneficiaries)) + validateAndPopulateErrors(validProjectBeneficiaries, existingProjectBeneficiaries, errorDetailsMap); + } + + return errorDetailsMap; + } + + /** + * This method retrieves existing ProjectBeneficiary entities based on their IDs. + * + * @param validProjectBeneficiaries List of valid ProjectBeneficiary entities. + * @return A list of existing ProjectBeneficiary entities. + */ + private List getExistingProjectBeneficiaries(List validProjectBeneficiaries) { + List existingProjectBeneficiaries = null; + + // Build a search request to find existing voucher tags + ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() + .id(validProjectBeneficiaries.stream().map(ProjectBeneficiary::getId).collect(Collectors.toList())) + .build(); + + try { + log.info("Fetching project beneficiary based on voucher tags"); + existingProjectBeneficiaries = projectBeneficiaryRepository.find( + projectBeneficiarySearch, + validProjectBeneficiaries.size(), 0, validProjectBeneficiaries.get(0).getTenantId(), null, false + ).getResponse(); + } catch (Exception e) { + log.error("Exception while fetching project beneficiary service : ", e); + throw new CustomException("PROJECT_BENEFICIARY_SEARCH_FAILED","Error occurred while fetching project beneficiary based on ids. "+e); + } + return existingProjectBeneficiaries; + } + + /** + * This method validates and populates errors for ProjectBeneficiary entities with duplicate voucher tags. + * + * @param validProjectBeneficiaries List of valid ProjectBeneficiary entities. + * @param existingProjectBeneficiaries List of existing ProjectBeneficiary entities based on IDs. + * @param errorDetailsMap A map to store error details for duplicate voucher tags. + */ + private void validateAndPopulateErrors(List validProjectBeneficiaries, List existingProjectBeneficiaries, Map> errorDetailsMap) { + Map existingProjectBeneficiaryMap = existingProjectBeneficiaries.stream().collect(Collectors.toMap(ProjectBeneficiary::getId, projectBeneficiary -> projectBeneficiary)); + // Filter project beneficiaries that are valid and have invalid voucher tags + List invalidEntities = validProjectBeneficiaries.stream() + .filter(notHavingErrors()) + .filter(entity -> !existingProjectBeneficiaryMap.containsKey(entity.getId())) + .collect(Collectors.toList()); + + populateErrors(invalidEntities, errorDetailsMap); + + Map existingProjectBeneficiaryVoucherTagMap = existingProjectBeneficiaries.stream().filter(projectBeneficiary -> projectBeneficiary.getTag() != null).collect(Collectors.toMap(ProjectBeneficiary::getTag, projectBeneficiary -> projectBeneficiary)); + invalidEntities = validProjectBeneficiaries.stream() + .filter(notHavingErrors()) + .filter(projectBeneficiary -> isUpdated(projectBeneficiary, existingProjectBeneficiaryMap)) + .filter(projectBeneficiary -> isInvalid(projectBeneficiary, existingProjectBeneficiaryVoucherTagMap)) + .collect(Collectors.toList()); + + populateErrors(invalidEntities, errorDetailsMap); + } + + /** + * This method populates error details for a list of ProjectBeneficiary entities with duplicate voucher tags. + * + * @param invalidEntities List of ProjectBeneficiary entities with duplicate voucher tags. + * @param errorDetailsMap A map to store error details. + */ + private void populateErrors(List invalidEntities, Map> errorDetailsMap) { + // For each invalid entity, create an error and populate error details + invalidEntities.forEach(projectBeneficiary -> { + Error error = Error.builder().errorMessage("Project Beneficiary Tag Validation Failed").errorCode("INVALID_TAG").type(Error.ErrorType.NON_RECOVERABLE).exception(new CustomException("INVALID_TAG", "Project Beneficiary Tag Validation Failed")).build(); + populateErrorDetails(projectBeneficiary, error, errorDetailsMap); + }); + } + + /** + * This method checks if a ProjectBeneficiary entity is invalid based on its voucher tag. + * + * @param entity The ProjectBeneficiary entity to check. + * @param existingProjectBeneficiaryVoucherTagMap The map containing existing ProjectBeneficiary entities + * indexed by their voucher tags. + * @return true if the entity is invalid, false otherwise. + */ + private boolean isInvalid(ProjectBeneficiary entity, Map existingProjectBeneficiaryVoucherTagMap) { + String id = entity.getId(); + String tag = entity.getTag(); + + // Check if an entity with the same ID exists in the map and has a different tag + return existingProjectBeneficiaryVoucherTagMap.keySet().contains(tag) && !existingProjectBeneficiaryVoucherTagMap.get(tag).getId().equals(id); + } + + /** + * Checks if a ProjectBeneficiary entity is considered as updated based on its tag. + * + * @param entity The ProjectBeneficiary entity to check. + * @param existingProjectBeneficiaryMap A map containing existing ProjectBeneficiary entities based on their IDs. + * @return true if the entity is updated, false otherwise. + */ + private boolean isUpdated(ProjectBeneficiary entity, Map existingProjectBeneficiaryMap) { + String id = entity.getId(); + String tag = entity.getTag(); + + // Retrieve the existing ProjectBeneficiary object to compare + ProjectBeneficiary projectBeneficiaryFromSearch = existingProjectBeneficiaryMap.get(id); + + // check if existing ProjectBeneficiary Tag is null or not and if it is null whether it is updated or not + if(projectBeneficiaryFromSearch.getTag() == null) return tag != null; + + // Check if the tag of the current entity is equal to the tag of the existing entity + return ( !projectBeneficiaryFromSearch.getTag().equals(tag) + || ( tag != null && !tag.equals(projectBeneficiaryFromSearch.getTag()) )); + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/ValidatorUtils.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/ValidatorUtils.java new file mode 100644 index 00000000000..a692601b501 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/ValidatorUtils.java @@ -0,0 +1,39 @@ +package org.egov.project.validator.beneficiary; + +import org.egov.common.models.Error; +import org.egov.common.models.project.ProjectBeneficiary; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +public class ValidatorUtils { + /** + * This method validates the uniqueness of voucher tags among valid ProjectBeneficiary entities. + * + * @param validProjectBeneficiaries List of valid ProjectBeneficiary entities. + * @param errorDetailsMap A map to store error details for duplicate voucher tags. + */ + public static void validateUniqueTags(List validProjectBeneficiaries, Map> errorDetailsMap) { + // Group ProjectBeneficiaries by voucher tags + Map> map = validProjectBeneficiaries.stream().filter(projectBeneficiary -> projectBeneficiary.getTag() != null) + .collect(Collectors.groupingBy(ProjectBeneficiary::getTag)); + + // Find voucher tags with duplicates + List duplicates = map.values().stream() + .filter(projectBeneficiaries -> projectBeneficiaries.size() > 1) + .flatMap(List::stream) + .filter(notHavingErrors()) + .collect(Collectors.toList()); + + // Populate error details for entities with duplicate voucher tags + for (ProjectBeneficiary projectBeneficiary : duplicates) { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(projectBeneficiary, error, errorDetailsMap); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/facility/PfFacilityIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/facility/PfFacilityIdValidator.java index 0733300cf59..bec1a7ffa89 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/facility/PfFacilityIdValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/facility/PfFacilityIdValidator.java @@ -1,6 +1,7 @@ package org.egov.project.validator.facility; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; @@ -98,7 +99,7 @@ private List validateFacilityIds(List entityIds, FacilityBulkResponse.class); return response.getFacilities().stream().map(Facility::getId).collect(Collectors.toList()); } catch (Exception e) { - log.error("error while fetching facility list", e); + log.error("error while fetching facility list", ExceptionUtils.getStackTrace(e)); projectFacilities.forEach(b -> { Error error = getErrorForEntityWithNetworkError(); populateErrorDetails(b, error, errorDetailsMap); diff --git a/health-services/project/src/main/java/org/egov/project/validator/project/ProjectValidator.java b/health-services/project/src/main/java/org/egov/project/validator/project/ProjectValidator.java index 9082f5a36a8..266f664312d 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/project/ProjectValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/project/ProjectValidator.java @@ -1,35 +1,45 @@ package org.egov.project.validator.project; +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.jayway.jsonpath.JsonPath; +import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.ProjectSearchURLParams; import org.egov.common.models.project.Document; import org.egov.common.models.project.Project; import org.egov.common.models.project.ProjectRequest; +import org.egov.common.models.project.ProjectSearch; +import org.egov.common.models.project.ProjectSearchRequest; import org.egov.common.models.project.Target; import org.egov.project.config.ProjectConfiguration; -import org.egov.project.util.BoundaryUtil; +import org.egov.project.util.BoundaryV2Util; import org.egov.project.util.MDMSUtils; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - +import static org.egov.project.util.ProjectConstants.MASTER_ATTENDANCE_SESSION; import static org.egov.project.util.ProjectConstants.MASTER_DEPARTMENT; import static org.egov.project.util.ProjectConstants.MASTER_NATUREOFWORK; import static org.egov.project.util.ProjectConstants.MASTER_PROJECTTYPE; import static org.egov.project.util.ProjectConstants.MASTER_TENANTS; import static org.egov.project.util.ProjectConstants.MDMS_COMMON_MASTERS_MODULE_NAME; +import static org.egov.project.util.ProjectConstants.MDMS_HCM_ATTENDANCE_MODULE_NAME; import static org.egov.project.util.ProjectConstants.MDMS_TENANT_MODULE_NAME; @Component @@ -40,11 +50,15 @@ public class ProjectValidator { MDMSUtils mdmsUtils; @Autowired - BoundaryUtil boundaryUtil; + BoundaryV2Util boundaryV2Util; @Autowired ProjectConfiguration config; + @Autowired + @Qualifier("objectMapper") + ObjectMapper mapper; + /* Validates create Project request body */ public void validateCreateProjectRequest(ProjectRequest request) { Map errorMap = new HashMap<>(); @@ -61,6 +75,7 @@ public void validateCreateProjectRequest(ProjectRequest request) { //Verify MDMS Data // TODO: Uncomment and fix as per HCM once we get clarity // validateRequestMDMSData(request, tenantId, errorMap); + validateAttendanceSessionAgainstMDMS(request,errorMap,tenantId); //Get boundaries in list from all Projects in request body for validation Map> boundariesForValidation = getBoundaryForValidation(request.getProjects()); @@ -95,6 +110,64 @@ public void validateSearchProjectRequest(ProjectRequest project, Integer limit, throw new CustomException(errorMap); } + /* Validates Project search request body */ + public void validateSearchV2ProjectRequest(ProjectSearchRequest projectSearchRequest, @Valid ProjectSearchURLParams urlParams) { + Map errorMap = new HashMap<>(); + RequestInfo requestInfo = projectSearchRequest.getRequestInfo(); + ProjectSearch projectSearch = projectSearchRequest.getProject(); + + // Verify if RequestInfo and UserInfo is present + validateRequestInfo(requestInfo); + + // Verify if search project request parameters are valid + validateSearchProjectRequestParams( + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + projectSearch.getCreatedFrom(), + projectSearch.getCreatedTo() + ); + + // Check if tenant ID is present in the request + if (StringUtils.isBlank(urlParams.getTenantId())) { + log.error("Tenant ID is mandatory in Project request body"); + throw new CustomException("TENANT_ID", "Tenant ID is mandatory"); + } + + // Validate if at least one project search field is present + if (CollectionUtils.isEmpty(projectSearch.getId()) + && StringUtils.isBlank(projectSearch.getProjectTypeId()) + && StringUtils.isBlank(projectSearch.getName()) + && StringUtils.isBlank(projectSearch.getSubProjectTypeId()) + && (projectSearch.getStartDate() == null || projectSearch.getStartDate() == 0) + && (projectSearch.getEndDate() == null || projectSearch.getEndDate() == 0) + && (projectSearch.getCreatedFrom() == null || projectSearch.getCreatedFrom() == 0) + && (projectSearch.getBoundaryCode() == null || StringUtils.isBlank(projectSearch.getBoundaryCode()))) { + log.error("Any one project search field is required for Project Search"); + throw new CustomException("PROJECT_SEARCH_FIELDS", "Any one project search field is required"); + } + + // Validate that start date is less than or equal to end date + if ((projectSearch.getStartDate() != null && projectSearch.getEndDate() != null && projectSearch.getEndDate() != 0) + && (projectSearch.getStartDate().compareTo(projectSearch.getEndDate()) > 0)) { + log.error("Start date should be less than end date"); + throw new CustomException("INVALID_DATE", "Start date should be less than end date"); + } + + // Validate that if end date is provided, start date should also be provided + if ((projectSearch.getStartDate() == null || projectSearch.getStartDate() == 0) + && (projectSearch.getEndDate() != null && projectSearch.getEndDate() != 0)) { + log.error("Start date is required if end date is passed"); + throw new CustomException("INVALID_DATE", "Start date is required if end date is passed"); + } + + // If there are any collected errors, throw a CustomException with the error map + if (!errorMap.isEmpty()) { + throw new CustomException(errorMap); + } + } + + /* Validates Update Project request body */ public void validateUpdateProjectRequest(ProjectRequest request) { Map errorMap = new HashMap<>(); @@ -183,6 +256,11 @@ private void validateProjectRequest(List projects) { log.error("Start date should be less than end date"); errorMap.put("INVALID_DATE", "Start date should be less than end date"); } + if (project.getStartDate() != null && project.getEndDate() != null && project.getEndDate() != 0 + && project.getEndDate().compareTo(Instant.ofEpochMilli(project.getStartDate()).plus(Duration.ofDays(1)).toEpochMilli()) < 0) { + log.error("Start date and end date difference should at least be 1 day."); + errorMap.put("INVALID_DATE", "Start date and end date difference should at least be 1 day."); + } if (project.getAddress() != null && StringUtils.isNotBlank(project.getAddress().getBoundary()) && StringUtils.isBlank(project.getAddress().getBoundaryType()) ) { log.error("Boundary Type is mandatory if boundary is present in Project request body"); errorMap.put("BOUNDARY", "Boundary Type is mandatory if boundary is present in Project request body"); @@ -303,6 +381,51 @@ private void validateMDMSData(List projects, Object mdmsData, Map errorMap, String tenantId) { + String rootTenantId = tenantId.split("\\.")[0]; + ObjectMapper objectMapper = new ObjectMapper(); + String numberOfSessions = null; + + //Get MDMS data using create project request and tenantId + Object mdmsData = mdmsUtils.mDMSCall(projectRequest, rootTenantId); + final String jsonPathForAttendanceSession = "$.MdmsRes." + MDMS_HCM_ATTENDANCE_MODULE_NAME + "." + MASTER_ATTENDANCE_SESSION + ".*"; + List attendanceRes = null; + try { + attendanceRes = JsonPath.read(mdmsData, jsonPathForAttendanceSession); + } catch (Exception e) { + log.error(e.getMessage()); + throw new CustomException("JSONPATH_ERROR", "Failed to parse mdms response"); + } + + for (Project project : projectRequest.getProjects()) { + JsonNode additionalDetails = null; + try { + Object additionalDetailsObj = project.getAdditionalDetails(); + String additionalDetailsStr = objectMapper.writeValueAsString(additionalDetailsObj); + additionalDetails = objectMapper.readTree(additionalDetailsStr); + + JsonNode numberOfSessionsNode = additionalDetails.get("numberOfSessions"); + if (numberOfSessionsNode != null && numberOfSessionsNode.isTextual()) { + numberOfSessions = numberOfSessionsNode.asText(); + log.info("Number of sessions: " + numberOfSessions); + } else { + log.info("numberOfSessions field not found in project's additonal Details"); + } + + } catch (ClassCastException e) { + log.error("Not able to parse additional details object", e); + } catch (Exception e) { + log.error("An unexpected error occurred while getting AdditionalDetails", e); + } + + // Validate numberOfSessions + if (!StringUtils.isBlank(numberOfSessions) && !attendanceRes.contains(numberOfSessions)) { + log.error("The number of attendance sessions " + numberOfSessions + " is not present in MDMS"); + errorMap.put("INVALID_NUMBER_OF_ATTENDANCE_SESSIONS", "The number of attendance sessions: " + numberOfSessions + " is not present in MDMS"); + } + } + } + /* Validate Project Request MDMS data */ private void validateRequestMDMSData(ProjectRequest request, String tenantId, Map errorMap) { String rootTenantId = tenantId.split("\\.")[0]; @@ -340,7 +463,7 @@ private Map> getBoundaryForValidation(List project /* Validates Boundary data with location service */ private void validateBoundary(Map> boundaries, String tenantId, RequestInfo requestInfo, Map errorMap) { if (boundaries.size() > 0) { - boundaryUtil.validateBoundaryDetails(boundaries, tenantId, requestInfo, config.getLocationHierarchyType()); + boundaryV2Util.validateBoundaryDetails(boundaries, tenantId, requestInfo, config.getLocationHierarchyType()); } } @@ -350,7 +473,17 @@ public void validateUpdateAgainstDB(List projectsFromRequest, List p.getId().equals(project.getId())).findFirst().orElse(null); @@ -359,6 +492,8 @@ public void validateUpdateAgainstDB(List projectsFromRequest, List projectsFromRequest, List projects, List parent } log.info("Parent projects validated against DB"); } -} +} \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java index 87e00f33266..7491e024ec3 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java @@ -2,12 +2,19 @@ import digit.models.coremodels.UserSearchRequest; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.User; +import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; +import org.egov.common.models.individual.Individual; +import org.egov.common.models.individual.IndividualBulkResponse; +import org.egov.common.models.individual.IndividualSearch; +import org.egov.common.models.individual.IndividualSearchRequest; import org.egov.common.models.project.ProjectStaff; import org.egov.common.models.project.ProjectStaffBulkRequest; import org.egov.common.service.UserService; import org.egov.common.validator.Validator; +import org.egov.project.config.ProjectConfiguration; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -34,8 +41,16 @@ public class PsUserIdValidator implements Validator> validate(ProjectStaffBulkRequest request) List entities = request.getProjectStaff(); Map> errorDetailsMap = new HashMap<>(); - List userIds = new ArrayList<>(entities.stream() + List userIds = entities.stream() .filter(notHavingErrors()) - .map(ProjectStaff::getUserId) - .collect(Collectors.toSet())); + .map(ProjectStaff::getUserId).distinct().collect(Collectors.toList()); + final String tenantId = getTenantId(entities); + Map uMap = getIdToObjMap(entities, + getMethod(GET_USER_ID, getObjClass(entities))); if (!userIds.isEmpty()) { - UserSearchRequest userSearchRequest = new UserSearchRequest(); - userSearchRequest.setTenantId(getTenantId(entities)); - userSearchRequest.setUuid(userIds); - - Map uMap = getIdToObjMap(entities, - getMethod(GET_USER_ID, getObjClass(entities))); + List validUserIds = new ArrayList<>(); try { - List validUserIds = userService - .search(userSearchRequest) - .stream() - .map(User::getUuid) - .collect(Collectors.toList()); + if ("egov-user".equalsIgnoreCase(projectConfiguration.getEgovUserIdValidator())) { + UserSearchRequest userSearchRequest = new UserSearchRequest(); + userSearchRequest.setTenantId(tenantId); + userSearchRequest.setUuid(userIds); + validUserIds = userService + .search(userSearchRequest) + .stream() + .map(User::getUuid) + .collect(Collectors.toList()); + } else if ("individual".equalsIgnoreCase(projectConfiguration.getEgovUserIdValidator())) { + IndividualSearchRequest individualSearchRequest = IndividualSearchRequest.builder() + .individual(IndividualSearch.builder() + // assuming this is "id" field of the individual payload + .id(userIds) + .build()) + .build(); + validUserIds = serviceRequestClient.fetchResult( + new StringBuilder(projectConfiguration.getIndividualServiceHost() + + projectConfiguration.getIndividualServiceSearchUrl() + + "?limit=" + projectConfiguration.getSearchApiLimit() + + "&offset=0&tenantId=" + tenantId), + individualSearchRequest, + IndividualBulkResponse.class).getIndividual().stream() + .map(Individual::getId) + .collect(Collectors.toList()); + } for (Map.Entry entry : uMap.entrySet()) { if (!validUserIds.contains(entry.getKey())) { ProjectStaff staff = entry.getValue(); @@ -69,7 +102,7 @@ public Map> validate(ProjectStaffBulkRequest request) } } } catch (Exception exception) { - log.error("error while validating users", exception); + log.error("error while validating users", ExceptionUtils.getStackTrace(exception)); entities.stream().filter(notHavingErrors()).forEach(b -> { Error error = getErrorForEntityWithNetworkError(); populateErrorDetails(b, error, errorDetailsMap); diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtExistentEntityValidator.java new file mode 100644 index 00000000000..ba4ebc24889 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtExistentEntityValidator.java @@ -0,0 +1,101 @@ +package org.egov.project.validator.task; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.Task; +import org.egov.common.models.project.TaskBulkRequest; +import org.egov.common.models.project.TaskSearch; +import org.egov.common.validator.Validator; +import org.egov.project.repository.ProjectTaskRepository; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of ProjectTask entities with the given client reference IDs. + * This validator ensures that the Task entities provided in the bulk request do not have duplicate client reference IDs in the database. + * + * The validation checks if each Task entity's client reference ID is unique across the database, + * and if a duplicate ID is found, it adds an error to the map with the entity. + * + * @author: kanishq-egov + */ +@Component +@Order(value = 1) +@Slf4j +public class PtExistentEntityValidator implements Validator { + + private final ProjectTaskRepository projectTaskRepository; + + /** + * Constructor to initialize the ProjectTaskRepository dependency. + * + * @param projectTaskRepository The repository for ProjectTask entities. + * This repository is used to query the database and check if entities with the given client reference IDs exist. + */ + public PtExistentEntityValidator(ProjectTaskRepository projectTaskRepository) { + this.projectTaskRepository = projectTaskRepository; + } + + /** + * Validates the existence of Task entities with the given client reference IDs. + * + * This method checks if any of the Task entities in the provided bulk request already exist in the database based on their client reference IDs. + * If an entity with a client reference ID already exists, an error is added to the map for that entity. + * + * @param request The bulk request containing Task entities to be validated. + * @return A map where the key is a Task entity and the value is a list of associated Error details. + * The map contains entries only for entities with errors (i.e., those whose client reference IDs already exist in the database). + */ + @Override + public Map> validate(TaskBulkRequest request) { + // Initialize a map to store Task entities and their associated error details. + Map> errorDetailsMap = new HashMap<>(); + + // Extract the list of Task entities from the request. + List entities = request.getTasks(); + + // Extract client reference IDs from Task entities that do not have existing errors. + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) // Filter out entities that already have errors. + .map(Task::getClientReferenceId) // Map to extract client reference IDs. + .collect(Collectors.toList()); // Collect the IDs into a list. + + // Create a map for quick lookup of Task entities by client reference ID. + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty. + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map. + + // Create a search object to query for existing entities based on client reference IDs. + TaskSearch taskSearch = TaskSearch.builder() + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search. + .build(); + + // Check if the client reference ID list is not empty before querying the database. + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing entities with the given client reference IDs. + List existingClientReferenceIds = projectTaskRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, add an error to the map for the corresponding Task entity. + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation. + Error error = getErrorForUniqueEntity(); + // Populate error details for the individual Task entity associated with the client reference ID. + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); + }); + } + + // Return the map containing Task entities and their associated error details. + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java new file mode 100644 index 00000000000..03838764dce --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java @@ -0,0 +1,76 @@ +package org.egov.project.validator.task; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.Task; +import org.egov.common.models.project.TaskBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.util.ProjectConstants; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.project.util.ProjectConstants.TASK_NOT_ALLOWED; + +/** + * To Validate when task resource is empty or null + */ +@Component +@Order(value = 1) +@Slf4j +public class PtIsResouceEmptyValidator implements Validator { + + private final ProjectConfiguration projectConfiguration; + + @Autowired + public PtIsResouceEmptyValidator(ProjectConfiguration projectConfiguration) { + this.projectConfiguration = projectConfiguration; + } + + /** + * Returns all the invalid objects in the request based on the task resources. + * @param request of TaskBulkRequest class + * @return errorDetailsMap + */ + public Map> validate(TaskBulkRequest request) { + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getTasks(); + if(!entities.isEmpty()) { + entities.forEach(task -> { + if (CollectionUtils.isEmpty(task.getResources()) && + !projectConfiguration.getNoResourceStatuses().contains(task.getStatus().toString())) { + /** + * If the task resource is empty or null and task status is not BENEFICIARY_REFUSED it is invalid + */ + String errorMessage = ProjectConstants.TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE + + String.join(ProjectConstants.OR, projectConfiguration.getNoResourceStatuses()); + Error error = Error.builder() + .errorMessage(errorMessage) + .errorCode(TASK_NOT_ALLOWED) + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException(TASK_NOT_ALLOWED, errorMessage)).build(); + populateErrorDetails(task, error, errorDetailsMap); + } else if (!CollectionUtils.isEmpty(task.getResources()) && projectConfiguration.getNoResourceStatuses().contains(task.getStatus().toString())) { + /** + * If the task resource is not empty and task status is BENEFICIARY_REFUSED + */ + Error error = Error.builder() + .errorMessage(ProjectConstants.TASK_NOT_ALLOWED_BENEFICIARY_REFUSED_RESOURCE_EMPTY_ERROR_MESSAGE) + .errorCode(TASK_NOT_ALLOWED) + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException(TASK_NOT_ALLOWED, ProjectConstants.TASK_NOT_ALLOWED_BENEFICIARY_REFUSED_RESOURCE_EMPTY_ERROR_MESSAGE)).build(); + populateErrorDetails(task, error, errorDetailsMap); + } + }); + } + return errorDetailsMap; + } +} \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtNonExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtNonExistentEntityValidator.java index 16b94a50ae0..5a1ceaa0b3b 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtNonExistentEntityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtNonExistentEntityValidator.java @@ -1,26 +1,27 @@ package org.egov.project.validator.task; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskBulkRequest; +import org.egov.common.models.project.TaskSearch; import org.egov.common.validator.Validator; import org.egov.project.repository.ProjectTaskRepository; +import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.ReflectionUtils; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdMethod; import static org.egov.common.utils.CommonUtils.getIdToObjMap; import static org.egov.common.utils.CommonUtils.getMethod; @@ -55,10 +56,30 @@ public Map> validate(TaskBulkRequest request) { Method idMethod = getMethod(GET_ID, objClass); Map eMap = getIdToObjMap(entities .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + // Lists to store IDs and client reference IDs + List idList = new ArrayList<>(); + List clientReferenceIdList = new ArrayList<>(); + // Extract IDs and client reference IDs from Project Task entities + entities.forEach(entity -> { + idList.add(entity.getId()); + clientReferenceIdList.add(entity.getClientReferenceId()); + }); if (!eMap.isEmpty()) { - List entityIds = new ArrayList<>(eMap.keySet()); - List existingEntities = projectTaskRepository.findById(entityIds, - getIdFieldName(idMethod), false); + TaskSearch taskSearch = TaskSearch.builder() + .clientReferenceId(clientReferenceIdList) + .id(idList) + .build(); + + List existingEntities; + try { + // Query the repository to find existing entities + existingEntities = projectTaskRepository.find(taskSearch, entities.size(), 0, + entities.get(0).getTenantId(), null, false).getResponse(); + } catch (Exception e) { + // Handle query builder exception + log.error("Search failed for ProjectTask with error: {}", e.getMessage(), e); + throw new CustomException("SEARCH_FAILED", "Search Failed for given ProjectTask, " + e.getMessage()); + } List nonExistentEntities = checkNonExistentEntities(eMap, existingEntities, idMethod); nonExistentEntities.forEach(task -> { @@ -67,10 +88,10 @@ public Map> validate(TaskBulkRequest request) { }); existingEntities.forEach(task -> { - validateSubEntity(errorDetailsMap, eMap, task, + if(task.getAddress() != null) validateSubEntity(errorDetailsMap, eMap, task, Collections.singletonList(task.getAddress()), GET_ADDRESS); - validateSubEntity(errorDetailsMap, eMap, task, + if(task.getResources() != null) validateSubEntity(errorDetailsMap, eMap, task, task.getResources(), GET_RESOURCES); }); } @@ -85,10 +106,10 @@ private void validateSubEntity(Map> errorDetailsMap, String getSubEntityMethodName) { Object objFromReq = ReflectionUtils.invokeMethod(getMethod(getSubEntityMethodName, Task.class), eMap.get(entity.getId())); - List subEntitiesInReq; + List subEntitiesInReq = null; if (objFromReq instanceof List) { subEntitiesInReq = (List) objFromReq; - } else { + } else if(objFromReq != null) { // if else condition here is added to prevent creating a list of null values, and if objFromReq is null then it will bypass line 116 till end of function. subEntitiesInReq = (List) Collections.singletonList(objFromReq); } diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtProductVariantIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtProductVariantIdValidator.java index bef18b723b5..c59928aa153 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtProductVariantIdValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtProductVariantIdValidator.java @@ -17,6 +17,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; import java.util.ArrayList; import java.util.HashMap; @@ -62,6 +63,8 @@ public Map> validate(TaskBulkRequest request) { .filter(notHavingErrors()).collect(Collectors.toList()); if (!entities.isEmpty()) { for (Task task : entities) { + if(CollectionUtils.isEmpty(task.getResources())) + continue; Set productVariantIds = new HashSet<>(getIdList(task.getResources(), getIdMethod(task.getResources(), "productVariantId"))); try { diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java new file mode 100644 index 00000000000..e3be161fabb --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java @@ -0,0 +1,237 @@ +package org.egov.project.validator.task; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.mdms.MasterDetail; +import digit.models.coremodels.mdms.MdmsCriteria; +import digit.models.coremodels.mdms.MdmsCriteriaReq; +import digit.models.coremodels.mdms.ModuleDetail; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.Error; +import org.egov.common.models.project.Task; +import org.egov.common.models.project.TaskBulkRequest; +import org.egov.common.models.project.TaskQuantity; +import org.egov.common.models.project.TaskResource; +import org.egov.common.service.MdmsService; +import org.egov.common.utils.CommonUtils; +import org.egov.common.validator.Validator; +import org.egov.project.config.ProjectConfiguration; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import static org.egov.project.Constants.INTERNAL_SERVER_ERROR; +import static org.egov.project.Constants.MDMS_RESPONSE; +import static org.egov.project.Constants.TASK_QUANTITY; +import static org.egov.project.util.ProjectConstants.TASK_NOT_ALLOWED; + +/** + * The PtResourceQuantityValidator class is responsible for validating the resource quantity of tasks in a bulk request. + * It checks whether the quantity adheres to the specified pattern defined in the project configuration. + * + * @author kanishq-egov + */ +@Component +@Order(value = 3) +@Slf4j +public class PtResourceQuantityValidator implements Validator { + private final ProjectConfiguration projectConfiguration; + + private final MdmsService mdmsService; + + /** + * Constructor for PtResourceQuantityValidator. + * + * @param projectConfiguration The configuration containing settings for the project module. + */ + public PtResourceQuantityValidator(ProjectConfiguration projectConfiguration, MdmsService mdmsService) { + this.projectConfiguration = projectConfiguration; + this.mdmsService = mdmsService; + } + + /** + * Validates the resource quantity of tasks in a bulk request. + * + * @param request The TaskBulkRequest containing a list of tasks. + * @return A map containing tasks with associated error details. + */ + @Override + public Map> validate(TaskBulkRequest request) { + // Map to store error details for each task + Map> errorDetailsMap = new HashMap<>(); + + // Extract the list of tasks from the request + List entities = request.getTasks(); + + // Check if the list is not empty + if(!entities.isEmpty()) { + entities.forEach(task -> { + List errors = new ArrayList<>(); + // Extract the list of task resources + List taskResources = task.getResources(); + if(!CollectionUtils.isEmpty(taskResources)) { + for(TaskResource taskResource : taskResources){ + Error error = validateResourceQuantity(taskResource, request.getRequestInfo()); + if(error != null){ + errors.add(error); + } + } + } + if (!errors.isEmpty()){ + errorDetailsMap.put(task,errors); + } + }); + } + return errorDetailsMap; + } + + /** + * Validates the resource quantity for a single task resource. + * + * @param taskResource The task resource to be validated. + * @param requestInfo The request information. + * @return An Error object if validation fails, else null. + */ + private Error validateResourceQuantity(TaskResource taskResource, RequestInfo requestInfo){ + String productVariantId = taskResource.getProductVariantId(); + String regex = getRegex(productVariantId, taskResource.getTenantId(), requestInfo); + String errorMessage = getErrorMessage(productVariantId, taskResource.getTenantId(), requestInfo); + if(regex == null){ + log.error("Failed to fetch regex for product variant id: {}",productVariantId); + return Error.builder() + .errorMessage("Failed to fetch Regex") + .errorCode(TASK_NOT_ALLOWED) + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException(TASK_NOT_ALLOWED, "Failed to Fetch Regex Pattern")) + .build(); + } + if(!CommonUtils.isValidPattern(Double.toString(taskResource.getQuantity()),regex)){ + String productVariantIdErrorMessage = (errorMessage+ " for product variant id: "+ productVariantId); + return Error.builder() + .errorMessage(productVariantIdErrorMessage) + .errorCode(TASK_NOT_ALLOWED) + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException(TASK_NOT_ALLOWED,errorMessage)) + .build(); + } + return null; + } + + /** + * Retrieves the regex pattern from MDMS for the given product variant ID. + * + * @param productVariantId The ID of the product variant. + * @param tenantId The tenant ID. + * @param requestInfo The request information. + * @return The regex pattern if found, otherwise null. + */ + private String getRegex(String productVariantId,String tenantId, RequestInfo requestInfo){ + List mdmsData = mdmsCall(tenantId, requestInfo); + for(TaskQuantity data : mdmsData){ + if (data.getId().contains(productVariantId)){ + return data.getRegex(); + }else{ + log.error("Failed to fetch regex for product variant ID: {}", productVariantId); + } + } + return null; + } + + /** + * Retrieves the error message from MDMS for the given product variant ID. + * + * @param productVariantId The ID of the product variant. + * @param tenantId The tenant ID. + * @param requestInfo The request information. + * @return The error message if found, otherwise null. + */ + private String getErrorMessage(String productVariantId,String tenantId, RequestInfo requestInfo){ + List mdmsData = mdmsCall(tenantId, requestInfo); + for(TaskQuantity data : mdmsData){ + if (data.getId().contains(productVariantId)){ + return data.getErrorMessage(); + }else{ + log.error("Failed to fetch error message for product variant ID: {}", productVariantId); + } + } + return null; + } + + /** + * Makes a call to MDMS to fetch task quantity data. + * + * @param tenantId The tenant ID. + * @param requestInfo The request information. + * @return A list of TaskQuantity objects. + */ + private List mdmsCall(String tenantId, RequestInfo requestInfo){ + JsonNode response = fetchMdmsResponse(requestInfo,tenantId, TASK_QUANTITY, projectConfiguration.getTaskMdmsModule()); + return convertToTaskQuantityList(response); + } + + /** + * Converts JSON response to a list of TaskQuantity objects. + * + * @param jsonNode The JSON node containing task quantity data. + * @return A list of TaskQuantity objects. + */ + private List convertToTaskQuantityList(JsonNode jsonNode) { + JsonNode taskTypesNode = jsonNode.get(projectConfiguration.getTaskMdmsModule()).withArray(TASK_QUANTITY); + return new ObjectMapper().convertValue(taskTypesNode, new TypeReference>() { + }); + } + + /** + * Makes a call to MDMS service to fetch MDMS configuration data. + * + * @param requestInfo The request information. + * @param tenantId The tenant ID. + * @param name The name of the MDMS configuration. + * @param moduleName The name of the MDMS module. + * @return The MDMS response JSON node. + */ + private JsonNode fetchMdmsResponse(RequestInfo requestInfo, String tenantId, String name, String moduleName){ + MdmsCriteriaReq serviceRegistry = getMdmsRequest(requestInfo, tenantId, name, moduleName); + try{ + return mdmsService.fetchConfig(serviceRegistry, JsonNode.class).get(MDMS_RESPONSE); + } catch(Exception e){ + throw new CustomException(INTERNAL_SERVER_ERROR, "Error while fetching mdms config"); + } + } + + /** + * Prepares MDMS request object. + * + * @param requestInfo The request information. + * @param tenantId The tenant ID. + * @param masterName The name of the master. + * @param moduleName The name of the module. + * @return The MDMS criteria request object. + */ + private MdmsCriteriaReq getMdmsRequest(RequestInfo requestInfo, String tenantId, String masterName, String moduleName){ + MasterDetail masterDetail = new MasterDetail(); + masterDetail.setName(masterName); + List masterDetailsList = new ArrayList<>(); + masterDetailsList.add(masterDetail); + ModuleDetail moduleDetail = new ModuleDetail(); + moduleDetail.setMasterDetails(masterDetailsList); + moduleDetail.setModuleName(moduleName); + List moduleDetailList = new ArrayList<>(); + moduleDetailList.add(moduleDetail); + MdmsCriteria mdmsCriteria = new MdmsCriteria(); + mdmsCriteria.setTenantId(tenantId.split("\\.")[0]); + mdmsCriteria.setModuleDetails(moduleDetailList); + MdmsCriteriaReq mdmsCriteriaReq = new MdmsCriteriaReq(); + mdmsCriteriaReq.setMdmsCriteria(mdmsCriteria); + mdmsCriteriaReq.setRequestInfo(requestInfo); + return mdmsCriteriaReq; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtRowVersionValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtRowVersionValidator.java index 48332dfcbe7..435c330daaf 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtRowVersionValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtRowVersionValidator.java @@ -49,7 +49,7 @@ public Map> validate(TaskBulkRequest request) { if (!eMap.isEmpty()) { List entityIds = new ArrayList<>(eMap.keySet()); List existingEntities = projectTaskRepository.findById(entityIds, - getIdFieldName(idMethod), false); + getIdFieldName(idMethod), false).getResponse(); List entitiesWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(eMap, existingEntities, idMethod); entitiesWithMismatchedRowVersion.forEach(individual -> { diff --git a/health-services/project/src/main/java/org/egov/project/validator/useraction/UaBoundaryValidator.java b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaBoundaryValidator.java new file mode 100644 index 00000000000..4f0394c1556 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaBoundaryValidator.java @@ -0,0 +1,125 @@ +package org.egov.project.validator.useraction; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.core.Boundary; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.web.models.boundary.BoundaryResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +/** + * Validator class for validating userAction boundaries. + */ +@Component +@Order(value = 4) +@Slf4j +public class UaBoundaryValidator implements Validator { + + private final ServiceRequestClient serviceRequestClient; + + private final ProjectConfiguration projectConfiguration; + + /** + * Constructor to initialize the HBoundaryValidator. + * + * @param serviceRequestClient Service request client for making HTTP requests + * @param projectConfiguration Configuration properties for the userAction module + */ + public UaBoundaryValidator(ServiceRequestClient serviceRequestClient, ProjectConfiguration projectConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.projectConfiguration = projectConfiguration; + } + + /** + * Validates the userActions' boundaries. + * + * @param request the bulk request containing userActions + * @return a map containing userActions with their corresponding list of errors + */ + @Override + public Map> validate(UserActionBulkRequest request) { + log.debug("Validating userActions boundaries."); + // Create a HashMap to store error details for each userAction + HashMap> errorDetailsMap = new HashMap<>(); + + // Filter userActions with non-null addresses + List entitiesWithValidBoundaries = request.getUserActions().parallelStream() + .filter(userAction -> Objects.nonNull(userAction.getBoundaryCode())) // Exclude null boundary codes + .collect(Collectors.toList()); + + Map> tenantIdUserActionMap = entitiesWithValidBoundaries.stream().collect(Collectors.groupingBy(UserAction::getTenantId)); + + tenantIdUserActionMap.forEach((tenantId, userActions) -> { + // Group userActions by locality code + Map> boundaryCodeUserActionsMap = userActions.stream() + .collect(Collectors.groupingBy( + userAction -> userAction.getBoundaryCode() // Group by boundary code + )); + + List boundaries = new ArrayList<>(boundaryCodeUserActionsMap.keySet()); + if(!CollectionUtils.isEmpty(boundaries)) { + try { + // Fetch boundary details from the service + log.debug("Fetching boundary details for tenantId: {}, boundaries: {}", tenantId, boundaries); + BoundaryResponse boundarySearchResponse = serviceRequestClient.fetchResult( + new StringBuilder(projectConfiguration.getBoundaryServiceHost() + + projectConfiguration.getBoundarySearchUrl() + +"?limit=" + boundaries.size() + + "&offset=0&tenantId=" + tenantId + + "&codes=" + String.join(",", boundaries)), + request.getRequestInfo(), + BoundaryResponse.class + ); + log.debug("Boundary details fetched successfully for tenantId: {}", tenantId); + + List invalidBoundaryCodes = new ArrayList<>(boundaries); + invalidBoundaryCodes.removeAll(boundarySearchResponse.getBoundary().stream() + .map(Boundary::getCode) + .collect(Collectors.toList()) + ); + + // Filter out userActions with invalid boundary codes + List userActionsWithInvalidBoundaries = boundaryCodeUserActionsMap.entrySet().stream() + .filter(entry -> invalidBoundaryCodes.contains(entry.getKey())) // filter invalid boundary codes + .flatMap(entry -> entry.getValue().stream()) // Flatten the list of userActions + .collect(Collectors.toList()); + + // Create an error object for userActions with invalid boundaries + Error error = Error.builder() + .errorMessage("Boundary code does not exist in db") + .errorCode("PROJECT_USER_ACTION_INVALID_BOUNDARY_ERROR") + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException("PROJECT_USER_ACTION_INVALID_BOUNDARY_ERROR", "Boundary code does not exist in db")) + .build(); + userActionsWithInvalidBoundaries.forEach(userAction -> { + // Populate error details for the userAction + populateErrorDetails(userAction, error, errorDetailsMap); + }); + + } catch (Exception e) { + log.error("Exception while searching boundaries for tenantId: {}", tenantId, e); + // Throw a custom exception if an error occurs during boundary search + throw new CustomException("BOUNDARY_SERVICE_SEARCH_ERROR","Error in while fetching boundaries from Boundary Service : " + e.getMessage()); + } + } + }); + + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/useraction/UaExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaExistentEntityValidator.java new file mode 100644 index 00000000000..e5f3ff7a026 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaExistentEntityValidator.java @@ -0,0 +1,99 @@ +package org.egov.project.validator.useraction; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.models.project.useraction.UserActionSearch; +import org.egov.common.validator.Validator; +import org.egov.project.repository.UserActionRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of UserAction entities based on their client reference IDs. + * This validator ensures that the UserAction entities in the bulk request do not have duplicate client reference IDs in the database. + * + * The validation checks if each UserAction entity's client reference ID already exists in the database. + * If a duplicate ID is found, it adds an error to the map with the entity. + * + * @author: kanishq-egov + */ +@Component +@Order(value = 1) +@Slf4j +public class UaExistentEntityValidator implements Validator { + private UserActionRepository userActionRepository; + + /** + * Constructs a UaExistentEntityValidator with the specified UserActionRepository. + * + * @param userActionRepository the repository used to validate UserAction entities. + */ + @Autowired + public UaExistentEntityValidator(UserActionRepository userActionRepository) { + this.userActionRepository = userActionRepository; + } + + /** + * Validates the existence of UserAction entities in the UserActionBulkRequest. + * Checks if the provided UserAction entities already exist in the database based on their client reference IDs. + * + * @param request the bulk request containing UserAction entities. + * @return a map of UserAction entities and their associated error details. + */ + @Override + public Map> validate(UserActionBulkRequest request) { + // Map to hold UserAction entities and their error details. + log.info("Validating existence of entities in UserActionBulkRequest with {} entities", request.getUserActions().size()); + Map> errorDetailsMap = new HashMap<>(); + + // Get the list of UserAction entities from the request. + List entities = request.getUserActions(); + + // Extract client reference IDs from UserAction entities that do not have existing errors. + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) // Filter out entities that already have errors. + .map(UserAction::getClientReferenceId) // Map to extract client reference IDs. + .collect(Collectors.toList()); // Collect the IDs into a list. + + // Create a map for quick lookup of UserAction entities by client reference ID. + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty. + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map. + + // Create a search object to query for existing UserAction entities based on client reference IDs. + UserActionSearch userActionSearch = UserActionSearch.builder() + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search. + .build(); + + // Check if the client reference ID list is not empty before querying the database. + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing UserAction entities with the given client reference IDs. + List existingClientReferenceIds = userActionRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.FALSE); + + // For each existing client reference ID, add an error to the map for the corresponding UserAction entity. + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation. + Error error = getErrorForUniqueEntity(); + // Populate error details for the individual UserAction entity associated with the client reference ID. + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); + }); + } + + // Return the map containing UserAction entities and their associated error details. + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/useraction/UaNonExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaNonExistentEntityValidator.java new file mode 100644 index 00000000000..c2b2534c1b0 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaNonExistentEntityValidator.java @@ -0,0 +1,96 @@ +package org.egov.project.validator.useraction; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.models.project.useraction.UserActionSearch; +import org.egov.common.validator.Validator; +import org.egov.project.repository.UserActionRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; +import static org.egov.project.Constants.GET_ID; + +@Component +@Order(value = 4) +@Slf4j +public class UaNonExistentEntityValidator implements Validator { + + private final UserActionRepository userActionRepository; + + @Autowired + public UaNonExistentEntityValidator(UserActionRepository userActionRepository) { + this.userActionRepository = userActionRepository; + } + + + @Override + public Map> validate(UserActionBulkRequest request) { + log.info("Validating existence of entities in UserActionBulkRequest with {} user actions", request.getUserActions().size()); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getUserActions(); + Class objClass = getObjClass(entities); + Method idMethod = getMethod(GET_ID, objClass); + Map eMap = getIdToObjMap(entities + .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + // Lists to store IDs and client reference IDs + List idList = new ArrayList<>(); + List clientReferenceIdList = new ArrayList<>(); + // Extract IDs and client reference IDs from Project UserAction entities + entities.forEach(entity -> { + idList.add(entity.getId()); + clientReferenceIdList.add(entity.getClientReferenceId()); + }); + if (!eMap.isEmpty()) { + UserActionSearch taskSearch = UserActionSearch.builder() + .clientReferenceId(clientReferenceIdList) + .id(idList) + .build(); + + URLParams urlParams = URLParams.builder() + .tenantId(entities.get(0).getTenantId()) + .limit(entities.size()) + .offset(0) + .includeDeleted(false) + .lastChangedSince(null) + .build(); + + List existingEntities; + try { + // Query the repository to find existing entities + existingEntities = userActionRepository.find(taskSearch, urlParams).getResponse(); + } catch (Exception e) { + // Handle query builder exception + log.error("Search failed for ProjectUserAction with error: {}", e.getMessage(), e); + throw new CustomException("PROJECT_USER_ACTION_SEARCH_FAILED", "Search failed for ProjectUserAction with clientReferenceId(s): " + + clientReferenceIdList + " and id(s): " + idList + ". Error: " + e.getMessage()); + } + List nonExistentEntities = checkNonExistentEntities(eMap, + existingEntities, idMethod); + nonExistentEntities.forEach(task -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(task, error, errorDetailsMap); + }); + } + + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/useraction/UaNullIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaNullIdValidator.java new file mode 100644 index 00000000000..52196f57f96 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaNullIdValidator.java @@ -0,0 +1,27 @@ +package org.egov.project.validator.useraction; + +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.validateForNullId; +import static org.egov.project.Constants.GET_USER_ACTION; + +@Component +@Order(value = 1) +@Slf4j +public class UaNullIdValidator implements Validator { + + @Override + public Map> validate(UserActionBulkRequest request) { + log.info("validating for null id"); + return validateForNullId(request, GET_USER_ACTION); + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/useraction/UaProjectIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaProjectIdValidator.java new file mode 100644 index 00000000000..b7c6ea63277 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaProjectIdValidator.java @@ -0,0 +1,96 @@ +package org.egov.project.validator.useraction; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.project.repository.ProjectRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentRelatedEntity; + +/** + * UaProjectIdValidator is responsible for validating the Project IDs in UserActionBulkRequest. + * It checks if the Project IDs present in the UserAction entities exist in the Project repository. + */ +@Component +@Order(value = 6) +@Slf4j +public class UaProjectIdValidator implements Validator { + + private ProjectRepository projectRepository; + + @Autowired + public UaProjectIdValidator(ProjectRepository projectRepository) { + this.projectRepository = projectRepository; + } + + /** + * Validates the Project IDs in the UserActionBulkRequest. + * It checks if the Project IDs present in the UserAction entities exist in the Project repository. + * + * @param request the UserActionBulkRequest containing UserAction entities to be validated. + * @return a map of UserAction entities to a list of Errors encountered during validation. + */ + @Override + public Map> validate(UserActionBulkRequest request) { + log.info("Starting validation of project IDs in UserActionBulkRequest with {} entities", request.getUserActions().size()); + + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getUserActions(); + + // Retrieve the class of the UserAction entities + Class objClass = getObjClass(entities); + log.debug("Retrieved UserAction entity class: {}", objClass.getName()); + + // Retrieve the method to get ProjectId from UserAction entities + Method idMethod = getMethod("getProjectId", objClass); + log.debug("Retrieved getProjectId method from UserAction entity class"); + + // Create a map of Project IDs to UserAction entities + Map eMap = getIdToObjMap(entities.stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + log.info("Created map of Project IDs to UserAction entities with {} entries", eMap.size()); + + if (!eMap.isEmpty()) { + List entityIds = new ArrayList<>(eMap.keySet()); + log.debug("List of Project IDs to validate: {}", entityIds); + + // Validate the Project IDs by checking their existence in the Project repository + List existingProjectIds = projectRepository.validateIds(entityIds, getIdFieldName(idMethod)); + log.info("Retrieved list of existing Project IDs from Project repository: {}", existingProjectIds); + + // Identify invalid UserAction entities with non-existent Project IDs + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + !existingProjectIds.contains(entity.getProjectId())).collect(Collectors.toList()); + log.info("Identified {} invalid UserAction entities with non-existent Project IDs", invalidEntities.size()); + + // Populate error details for invalid UserAction entities + invalidEntities.forEach(userAction -> { + Error error = getErrorForNonExistentRelatedEntity(userAction.getProjectId()); + populateErrorDetails(userAction, error, errorDetailsMap); + log.debug("Populated error details for UserAction with invalid Project ID: {}", userAction.getProjectId()); + }); + } else { + log.info("No Project IDs to validate as the map of Project IDs to UserAction entities is empty"); + } + + log.info("Completed validation of project IDs in UserActionBulkRequest"); + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/useraction/UaRowVersionValidator.java b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaRowVersionValidator.java new file mode 100644 index 00000000000..45c8381d120 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaRowVersionValidator.java @@ -0,0 +1,69 @@ +package org.egov.project.validator.useraction; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.project.repository.UserActionRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.getEntitiesWithMismatchedRowVersion; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForRowVersionMismatch; + +@Component +@Order(value = 5) +@Slf4j +public class UaRowVersionValidator implements Validator { + + private final UserActionRepository userActionRepository; + + @Autowired + public UaRowVersionValidator(UserActionRepository userActionRepository) { + this.userActionRepository = userActionRepository; + } + + + @Override + public Map> validate(UserActionBulkRequest request) { + log.info("validating row version"); + Map> errorDetailsMap = new HashMap<>(); + try { + + Method idMethod = getIdMethod(request.getUserActions()); + Map eMap = getIdToObjMap(request.getUserActions().stream() + .filter(notHavingErrors()) + .collect(Collectors.toList()), idMethod); + if (!eMap.isEmpty()) { + List entityIds = new ArrayList<>(eMap.keySet()); + List existingEntities = userActionRepository.findById(entityIds, + getIdFieldName(idMethod)).getResponse(); + List entitiesWithMismatchedRowVersion = + getEntitiesWithMismatchedRowVersion(eMap, existingEntities, idMethod); + entitiesWithMismatchedRowVersion.forEach(individual -> { + Error error = getErrorForRowVersionMismatch(); + populateErrorDetails(individual, error, errorDetailsMap); + }); + } + } catch (Exception e) { + log.error("Exception occurred during validation: {}", e.getMessage()); + throw new CustomException("PROJECT_USER_ACTION_PROJECT_ID_VALIDATION_ERROR", "Error occurred while validating project IDs"+e); + } + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/BandwidthController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/BandwidthController.java new file mode 100644 index 00000000000..848ec089f4c --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/BandwidthController.java @@ -0,0 +1,34 @@ +package org.egov.project.web.controllers; + +import io.swagger.annotations.ApiParam; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.utils.ResponseInfoFactory; +import org.egov.project.web.models.BandwidthCheckRequest; +import org.egov.project.web.models.BandwidthCheckResponse; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import jakarta.validation.Valid; + +@Controller +@RequestMapping("") +@Validated +@Slf4j +public class BandwidthController { + + + @RequestMapping(value = "/check/bandwidth", method = RequestMethod.POST) + public ResponseEntity checkBandwidth(@ApiParam(value = "Captures dummy json data", required = true) @Valid @RequestBody BandwidthCheckRequest request) { + log.info("Request received: {}", request); + return ResponseEntity.status(HttpStatus.OK).body(BandwidthCheckResponse.builder() + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .additionalFields(request.getAdditionalFields()) + .build()); + } +} diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/LocationCaptureController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/LocationCaptureController.java new file mode 100644 index 00000000000..2214594b313 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/LocationCaptureController.java @@ -0,0 +1,130 @@ +package org.egov.project.web.controllers; + +import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.models.project.useraction.UserActionBulkResponse; +import org.egov.common.models.project.useraction.UserActionSearchRequest; +import org.egov.common.producer.Producer; +import org.egov.common.utils.ResponseInfoFactory; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.service.LocationCaptureService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Controller for handling requests related to location capture tasks. + * Provides endpoints for creating and searching location capture tasks. + */ +@Controller +@RequestMapping("/user-location") +@Validated +@Slf4j +public class LocationCaptureController { + + private final HttpServletRequest httpServletRequest; + private final LocationCaptureService locationCaptureService; + private final Producer producer; + private final ProjectConfiguration projectConfiguration; + + /** + * Constructor for injecting dependencies into the LocationCaptureController. + * + * @param httpServletRequest The HttpServletRequest to capture request details. + * @param locationCaptureService The service for handling location capture logic. + * @param producer The producer for sending messages to Kafka topics. + * @param projectConfiguration Configuration properties related to the project. + */ + @Autowired + public LocationCaptureController( + HttpServletRequest httpServletRequest, + LocationCaptureService locationCaptureService, + Producer producer, + ProjectConfiguration projectConfiguration + ) { + this.httpServletRequest = httpServletRequest; + this.locationCaptureService = locationCaptureService; + this.producer = producer; + this.projectConfiguration = projectConfiguration; + } + + /** + * Endpoint for creating location capture tasks in bulk. + * Receives a UserActionBulkRequest object, processes it, and sends it to the appropriate Kafka topic. + * + * @param request The bulk request containing user actions to be created. + * @return A ResponseEntity containing the response info with HTTP status ACCEPTED. + */ + @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) + public ResponseEntity locationCaptureTaskV1BulkCreatePost( + @ApiParam(value = "Create Location Capture LocationCapture.", required = true) @Valid @RequestBody UserActionBulkRequest request) { + // Set the API ID in the request info using the current request URI. + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + + try { + // Send the request to the Kafka topic for bulk creation. + producer.push(projectConfiguration.getBulkCreateLocationCaptureTopic(), request); + } catch (Exception e) { + log.error("Error sending bulk create request for location captures to Kafka: {}", e.getMessage(), e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body( + ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), false) + ); + } + + // Create and return a ResponseInfo object with HTTP status ACCEPTED. + return ResponseEntity.status(HttpStatus.ACCEPTED).body( + ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), true) + ); + } + + /** + * Endpoint for searching location capture tasks based on given search criteria. + * Receives a UserActionSearchRequest object and returns the search results. + * + * @param urlParams URL parameters for the search. + * @param locationCaptureSearchRequest The request containing search criteria for location capture tasks. + * @return A ResponseEntity containing the search results with HTTP status OK. + * @throws Exception if there is an error during the search operation. + */ + @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) + public ResponseEntity locationCaptureTaskV2SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Search details of Location Capture.", required = true) @Valid @RequestBody UserActionSearchRequest locationCaptureSearchRequest + ) throws Exception { + + try { + // Perform the search using the locationCaptureService. + SearchResponse locationCaptureSearchResponse = locationCaptureService.search(locationCaptureSearchRequest, urlParams); + + // Build the response object with the search results and response info. + UserActionBulkResponse response = UserActionBulkResponse.builder() + .userActions(locationCaptureSearchResponse.getResponse()) + .totalCount(locationCaptureSearchResponse.getTotalCount()) + .responseInfo(ResponseInfoFactory.createResponseInfo(locationCaptureSearchRequest.getRequestInfo(), true)) + .build(); + + // Return the response with HTTP status OK. + return ResponseEntity.status(HttpStatus.OK).body(response); + } catch (Exception e) { + log.error("Error occurred during search operation for location captures: {}", e.getMessage(), e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body( + UserActionBulkResponse.builder() + .responseInfo(ResponseInfoFactory.createResponseInfo(locationCaptureSearchRequest.getRequestInfo(), false)) + .build() + ); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectApiController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectApiController.java index 806a61bdffa..1b74b7ab1d7 100644 --- a/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectApiController.java +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectApiController.java @@ -1,13 +1,24 @@ package org.egov.project.web.controllers; +import java.util.List; + import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.ProjectSearchURLParams; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; import org.egov.common.models.project.BeneficiaryBulkRequest; import org.egov.common.models.project.BeneficiaryBulkResponse; import org.egov.common.models.project.BeneficiaryRequest; import org.egov.common.models.project.BeneficiaryResponse; +import org.egov.common.models.project.BeneficiarySearchRequest; import org.egov.common.models.project.Project; import org.egov.common.models.project.ProjectBeneficiary; import org.egov.common.models.project.ProjectFacility; @@ -15,13 +26,16 @@ import org.egov.common.models.project.ProjectFacilityBulkResponse; import org.egov.common.models.project.ProjectFacilityRequest; import org.egov.common.models.project.ProjectFacilityResponse; +import org.egov.common.models.project.ProjectFacilitySearchRequest; import org.egov.common.models.project.ProjectRequest; import org.egov.common.models.project.ProjectResponse; +import org.egov.common.models.project.ProjectSearchRequest; import org.egov.common.models.project.ProjectStaff; import org.egov.common.models.project.ProjectStaffBulkRequest; import org.egov.common.models.project.ProjectStaffBulkResponse; import org.egov.common.models.project.ProjectStaffRequest; import org.egov.common.models.project.ProjectStaffResponse; +import org.egov.common.models.project.ProjectStaffSearchRequest; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskBulkRequest; import org.egov.common.models.project.TaskBulkResponse; @@ -36,27 +50,18 @@ import org.egov.project.service.ProjectService; import org.egov.project.service.ProjectStaffService; import org.egov.project.service.ProjectTaskService; -import org.egov.project.web.models.BeneficiarySearchRequest; -import org.egov.project.web.models.ProjectFacilitySearchRequest; -import org.egov.project.web.models.ProjectStaffSearchRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.util.List; -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-14T20:57:07.075+05:30") @Controller @RequestMapping("") @Validated @@ -101,6 +106,7 @@ public ProjectApiController(ObjectMapper objectMapper, HttpServletRequest httpSe @RequestMapping(value = "/beneficiary/v1/bulk/_create", method = RequestMethod.POST) public ResponseEntity projectBeneficiaryV1BulkCreatePost(@ApiParam(value = "Capture details of benificiary type.", required = true) @Valid @RequestBody BeneficiaryBulkRequest beneficiaryRequest) { + beneficiaryRequest.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); beneficiaryRequest.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); projectBeneficiaryService.putInCache(beneficiaryRequest.getProjectBeneficiaries()); producer.push(projectConfiguration.getBulkCreateProjectBeneficiaryTopic(), beneficiaryRequest); @@ -122,20 +128,21 @@ public ResponseEntity projectBeneficiaryV1CreatePost(@ApiPa } @RequestMapping(value = "/beneficiary/v1/_search", method = RequestMethod.POST) - public ResponseEntity projectBeneficiaryV1SearchPost(@ApiParam(value = "Project Beneficiary Search.", required = true) @Valid @RequestBody BeneficiarySearchRequest beneficiarySearchRequest, @NotNull - @Min(0) - @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull - @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { - List projectBeneficiaries = projectBeneficiaryService.search( + public ResponseEntity projectBeneficiaryV2SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Project Beneficiary Search.", required = true) @Valid @RequestBody BeneficiarySearchRequest beneficiarySearchRequest + ) throws Exception { + SearchResponse searchResponse = projectBeneficiaryService.search( beneficiarySearchRequest, - limit, - offset, - tenantId, - lastChangedSince, - includeDeleted + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() ); BeneficiaryBulkResponse beneficiaryResponse = BeneficiaryBulkResponse.builder() - .projectBeneficiaries(projectBeneficiaries) + .projectBeneficiaries(searchResponse.getResponse()) + .totalCount(searchResponse.getTotalCount()) .responseInfo(ResponseInfoFactory .createResponseInfo(beneficiarySearchRequest.getRequestInfo(), true)) .build(); @@ -207,20 +214,19 @@ public ResponseEntity projectFacilityV1BulkCreatePost(@ApiParam(va .createResponseInfo(request.getRequestInfo(), true)); } + @RequestMapping(value = "/facility/v1/_search", method = RequestMethod.POST) - public ResponseEntity projectFacilityV1SearchPost(@ApiParam(value = "Capture details of Project facility.", required = true) @Valid @RequestBody ProjectFacilitySearchRequest projectFacilitySearchRequest, - @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, - @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, - @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, - @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, - @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { + public ResponseEntity projectFacilityV2SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Capture details of Project facility.", required = true) @Valid @RequestBody ProjectFacilitySearchRequest projectFacilitySearchRequest + ) throws Exception { List projectFacilities = projectFacilityService.search( projectFacilitySearchRequest, - limit, - offset, - tenantId, - lastChangedSince, - includeDeleted + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() ); ProjectFacilityBulkResponse response = ProjectFacilityBulkResponse.builder() .projectFacilities(projectFacilities) @@ -298,20 +304,19 @@ public ResponseEntity projectStaffV1CreatePost(@ApiParam(value = " .createResponseInfo(request.getRequestInfo(), true)); } + @RequestMapping(value = "/staff/v1/_search", method = RequestMethod.POST) - public ResponseEntity projectStaffV1SearchPost(@ApiParam(value = "Capture details of Project staff.", required = true) @Valid @RequestBody ProjectStaffSearchRequest projectStaffSearchRequest, - @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, - @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, - @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, - @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, - @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { + public ResponseEntity projectStaffV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Capture details of Project staff.", required = true) @Valid @RequestBody ProjectStaffSearchRequest projectStaffSearchRequest + ) throws Exception { List projectStaffList = projectStaffService.search( projectStaffSearchRequest, - limit, - offset, - tenantId, - lastChangedSince, - includeDeleted + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() ); ProjectStaffBulkResponse response = ProjectStaffBulkResponse.builder() .projectStaff(projectStaffList) @@ -393,17 +398,23 @@ public ResponseEntity projectTaskBulkV1CreatePost(@ApiParam(value .createResponseInfo(request.getRequestInfo(), true)); } + @RequestMapping(value = "/task/v1/_search", method = RequestMethod.POST) - public ResponseEntity projectTaskV1SearchPost(@ApiParam(value = "Project Task Search.", required = true) @Valid @RequestBody TaskSearchRequest request, - @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, - @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, - @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, - @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, - @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) { - - List households = projectTaskService.search(request.getTask(), limit, offset, tenantId, lastChangedSince, includeDeleted); + public ResponseEntity projectTaskV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Project Task Search.", required = true) @Valid @RequestBody TaskSearchRequest taskSearchRequest + ) { + SearchResponse taskSearchResponse = projectTaskService.search( + taskSearchRequest.getTask(), + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() + ); + TaskBulkResponse response = TaskBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).tasks(households).build(); + .createResponseInfo(taskSearchRequest.getRequestInfo(), true)).tasks(taskSearchResponse.getResponse()).totalCount(taskSearchResponse.getTotalCount()).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } @@ -463,14 +474,52 @@ public ResponseEntity createProject(@ApiParam(value = "Details } @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) - public ResponseEntity searchProject(@ApiParam(value = "Details for the project.", required = true) @Valid @RequestBody ProjectRequest project, @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted , @ApiParam(value = "Used in project search API to specify if response should include project elements that are in the preceding hierarchy of matched projects.", defaultValue = "false") @Valid @RequestParam(value = "includeAncestors", required = false, defaultValue = "false") Boolean includeAncestors, @ApiParam(value = "Used in project search API to specify if response should include project elements that are in the following hierarchy of matched projects.", defaultValue = "false") @Valid @RequestParam(value = "includeDescendants", required = false, defaultValue = "false") Boolean includeDescendants, @ApiParam(value = "Used in project search API to limit the search results to only those projects whose creation date is after the specified 'createdFrom' date", defaultValue = "false") @Valid @RequestParam(value = "createdFrom", required = false) Long createdFrom, @ApiParam(value = "Used in project search API to limit the search results to only those projects whose creation date is before the specified 'createdTo' date", defaultValue = "false") @Valid @RequestParam(value = "createdTo", required = false) Long createdTo) { - List projects = projectService.searchProject(project, limit, offset, tenantId, lastChangedSince, includeDeleted, includeAncestors, includeDescendants, createdFrom, createdTo); + public ResponseEntity searchProject( + @ApiParam(value = "Details for the project.", required = true) @Valid @RequestBody ProjectRequest project, + @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, + @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, + @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, + @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, + @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted, + @ApiParam(value = "Used in project search API to specify if response should include project elements that are in the preceding hierarchy of matched projects.", defaultValue = "false") @Valid @RequestParam(value = "includeAncestors", required = false, defaultValue = "false") Boolean includeAncestors, + @ApiParam(value = "Used in project search API to specify if response should include project elements that are in the following hierarchy of matched projects.", defaultValue = "false") @Valid @RequestParam(value = "includeDescendants", required = false, defaultValue = "false") Boolean includeDescendants, + @ApiParam(value = "Used in project search API to limit the search results to only those projects whose creation date is after the specified 'createdFrom' date", defaultValue = "false") @Valid @RequestParam(value = "createdFrom", required = false) Long createdFrom, + @ApiParam(value = "Used in project search API to limit the search results to only those projects whose creation date is before the specified 'createdTo' date", defaultValue = "false") @Valid @RequestParam(value = "createdTo", required = false) Long createdTo + ) { + List projects = projectService.searchProject( + project, + limit, + offset, + tenantId, + lastChangedSince, + includeDeleted, + includeAncestors, + includeDescendants, + createdFrom, + createdTo + ); ResponseInfo responseInfo = ResponseInfoFactory.createResponseInfo(project.getRequestInfo(), true); Integer count = projectService.countAllProjects(project, tenantId, lastChangedSince, includeDeleted, createdFrom, createdTo); ProjectResponse projectResponse = ProjectResponse.builder().responseInfo(responseInfo).project(projects).totalCount(count).build(); return new ResponseEntity(projectResponse, HttpStatus.OK); } + @RequestMapping(value = "/v2/_search", method = RequestMethod.POST) + public ResponseEntity searchV2Project( + @Valid @ModelAttribute ProjectSearchURLParams urlParams, + @ApiParam(value = "Details for the project.", required = true) @Valid @RequestBody ProjectSearchRequest projectSearchRequest + ) { + List projects = projectService.searchProject(projectSearchRequest, urlParams); + ResponseInfo responseInfo = ResponseInfoFactory.createResponseInfo(projectSearchRequest.getRequestInfo(), true); + Integer count = projectService.countAllProjects(projectSearchRequest, urlParams); + ProjectResponse projectResponse = ProjectResponse.builder() + .responseInfo(responseInfo) + .project(projects) + .totalCount(count) + .build(); + return new ResponseEntity(projectResponse, HttpStatus.OK); + } + @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) public ResponseEntity updateProject(@ApiParam(value = "Details for the updated Project.", required = true) @Valid @RequestBody ProjectRequest project) { ProjectRequest enrichedProjectRequest = projectService.updateProject(project); diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectResourceApiController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectResourceApiController.java index 499123db26b..6f71ea7ef93 100644 --- a/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectResourceApiController.java +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectResourceApiController.java @@ -1,36 +1,34 @@ package org.egov.project.web.controllers; +import java.util.List; + import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.models.core.URLParams; import org.egov.common.models.project.ProjectResource; import org.egov.common.models.project.ProjectResourceBulkRequest; import org.egov.common.models.project.ProjectResourceBulkResponse; import org.egov.common.models.project.ProjectResourceRequest; import org.egov.common.models.project.ProjectResourceResponse; +import org.egov.common.models.project.ProjectResourceSearchRequest; import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; import org.egov.project.config.ProjectConfiguration; import org.egov.project.service.ProjectResourceService; -import org.egov.project.web.models.ProjectResourceSearchRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.util.List; -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-14T20:57:07.075+05:30") @Controller @RequestMapping("") @Validated @@ -72,16 +70,21 @@ public ResponseEntity resourceV1BulkCreatePost(@ApiParam(value = " } @RequestMapping(value = "/resource/v1/_search", method = RequestMethod.POST) - public ResponseEntity resourceV1SearchPost(@ApiParam( - value = "Search linkage of Project and resource.", required = true) @Valid @RequestBody - ProjectResourceSearchRequest request, @NotNull - @Min(0) - @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull - @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws QueryBuilderException { - - List projectResource = projectResourceService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); + public ResponseEntity resourceV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Search linkage of Project and resource.", required = true) @Valid @RequestBody ProjectResourceSearchRequest projectResourceSearchRequest + ) throws QueryBuilderException { + + List projectResource = projectResourceService.search( + projectResourceSearchRequest, + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() + ); ProjectResourceBulkResponse response = ProjectResourceBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).projectResource(projectResource).build(); + .createResponseInfo(projectResourceSearchRequest.getRequestInfo(), true)).projectResource(projectResource).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/UserActionController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/UserActionController.java new file mode 100644 index 00000000000..34a56ae9ca5 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/UserActionController.java @@ -0,0 +1,162 @@ +package org.egov.project.web.controllers; + +import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.models.project.useraction.UserActionBulkResponse; +import org.egov.common.models.project.useraction.UserActionSearchRequest; +import org.egov.common.producer.Producer; +import org.egov.common.utils.ResponseInfoFactory; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.service.UserActionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Controller for handling user action-related requests. + * Provides endpoints for creating, updating, and searching user actions. + */ +@Controller +@RequestMapping("/user-action") +@Validated +@Slf4j +public class UserActionController { + + private final HttpServletRequest httpServletRequest; + private final UserActionService userActionService; + private final Producer producer; + private final ProjectConfiguration projectConfiguration; + + /** + * Constructor for injecting dependencies into the UserActionController. + * + * @param httpServletRequest The HttpServletRequest to capture request details. + * @param userActionService The service for handling user action logic. + * @param producer The producer for sending messages to Kafka topics. + * @param projectConfiguration Configuration properties related to the project. + */ + @Autowired + public UserActionController( + HttpServletRequest httpServletRequest, + UserActionService userActionService, + Producer producer, + ProjectConfiguration projectConfiguration + ) { + this.httpServletRequest = httpServletRequest; + this.userActionService = userActionService; + this.producer = producer; + this.projectConfiguration = projectConfiguration; + } + + /** + * Endpoint for creating user actions in bulk. + * Receives a UserActionBulkRequest object, processes it, and sends it to the appropriate Kafka topic. + * + * @param request The bulk request containing user actions to be created. + * @return A ResponseEntity containing the response info with HTTP status ACCEPTED. + */ + @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) + public ResponseEntity userActionV1BulkCreatePost( + @ApiParam(value = "Capture linkage of Project and User Action UserAction.", required = true) @Valid @RequestBody UserActionBulkRequest request + ) { + // Set the API ID in the request info using the current request URI. + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + + try { + log.debug("Pushing user action bulk create request to Kafka topic: {}", projectConfiguration.getBulkCreateUserActionTopic()); + // Send the request to the Kafka topic for bulk creation. + producer.push(projectConfiguration.getBulkCreateUserActionTopic(), request); + log.info("Successfully pushed user action bulk create request to Kafka"); + } catch (Exception e) { + log.error("Failed to push user action bulk create request to Kafka", e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body( + ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), false) + ); + } + + // Create and return a ResponseInfo object with HTTP status ACCEPTED. + return ResponseEntity.status(HttpStatus.ACCEPTED).body( + ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), true) + ); + } + + /** + * Endpoint for searching user actions based on given search criteria. + * Receives a UserActionSearchRequest object and returns the search results. + * + * @param urlParams URL parameters for the search. + * @param request The request containing search criteria for user actions. + * @return A ResponseEntity containing the search results with HTTP status OK. + */ + @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) + public ResponseEntity userActionV2SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Capture details of Project User Action UserAction.", required = true) @Valid @RequestBody UserActionSearchRequest request + ) { + log.debug("Executing search with URLParams: {} and request: {}", urlParams, request); + + // Perform the search using the userActionService. + SearchResponse userActions; + try { + // Perform the search using the userActionService. + userActions = userActionService.search(request, urlParams); + log.info("Successfully searched for user actions: {}", userActions.getResponse().size()); + } catch (Exception e) { + log.error("Failed to search for user actions", e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); + } + + // Build the response object with the search results and response info. + UserActionBulkResponse response = UserActionBulkResponse.builder() + .userActions(userActions.getResponse()) + .totalCount(userActions.getTotalCount()) + .responseInfo(ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), true)) + .build(); + + // Return the response with HTTP status OK. + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + /** + * Endpoint for updating user actions in bulk. + * Receives a UserActionBulkRequest object, processes it, and sends it to the appropriate Kafka topic. + * + * @param request The bulk request containing user actions to be updated. + * @return A ResponseEntity containing the response info with HTTP status ACCEPTED. + */ + @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) + public ResponseEntity userActionV1BulkUpdatePost( + @ApiParam(value = "Capture linkage of Project and User Action UserAction.", required = true) @Valid @RequestBody UserActionBulkRequest request + ) { + // Set the API ID in the request info using the current request URI. + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + + try { + // Send the request to the Kafka topic for bulk update. + producer.push(projectConfiguration.getBulkUpdateUserActionTopic(), request); + } catch (Exception e) { + log.error("Failed to push user action bulk update request to Kafka", e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body( + ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), false) + ); + } + + // Create and return a ResponseInfo object with HTTP status ACCEPTED. + return ResponseEntity.status(HttpStatus.ACCEPTED).body( + ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), true) + ); + } +} diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectStaffSearchRequest.java b/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckRequest.java similarity index 54% rename from health-services/project/src/main/java/org/egov/project/web/models/ProjectStaffSearchRequest.java rename to health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckRequest.java index ce13fa1a73e..2a34df10592 100644 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectStaffSearchRequest.java +++ b/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckRequest.java @@ -7,33 +7,24 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.project.AdditionalFields; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; -/** -* ProjectStaffSearchRequest -*/ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") +@JsonIgnoreProperties(ignoreUnknown = true) @Data -@NoArgsConstructor @AllArgsConstructor +@NoArgsConstructor @Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectStaffSearchRequest { +public class BandwidthCheckRequest { @JsonProperty("RequestInfo") - @NotNull - @Valid - private RequestInfo requestInfo = null; - - @JsonProperty("ProjectStaff") - @NotNull - @Valid - private ProjectStaffSearch projectStaff = null; + private @NotNull @Valid RequestInfo requestInfo = null; + @JsonProperty("additionalFields") + private @Valid AdditionalFields additionalFields = null; } - diff --git a/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckResponse.java b/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckResponse.java new file mode 100644 index 00000000000..5fdcf303eaf --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckResponse.java @@ -0,0 +1,30 @@ +package org.egov.project.web.models; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.project.AdditionalFields; +import org.springframework.validation.annotation.Validated; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; + +@Validated +@JsonIgnoreProperties(ignoreUnknown = true) + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BandwidthCheckResponse { + + @JsonProperty("ResponseInfo") + private @NotNull @Valid ResponseInfo responseInfo = null; + + @JsonProperty("additionalFields") + private @Valid AdditionalFields additionalFields = null; +} diff --git a/health-services/project/src/main/java/org/egov/project/web/models/BeneficiarySearchRequest.java b/health-services/project/src/main/java/org/egov/project/web/models/BeneficiarySearchRequest.java index 87025f0202a..ba1cd058378 100644 --- a/health-services/project/src/main/java/org/egov/project/web/models/BeneficiarySearchRequest.java +++ b/health-services/project/src/main/java/org/egov/project/web/models/BeneficiarySearchRequest.java @@ -7,16 +7,17 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.project.ProjectBeneficiarySearch; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * BeneficiarySearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectBeneficiarySearch.java b/health-services/project/src/main/java/org/egov/project/web/models/ProjectBeneficiarySearch.java deleted file mode 100644 index c9f8a61034b..00000000000 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectBeneficiarySearch.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.egov.project.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Table; -import org.springframework.validation.annotation.Validated; - -import javax.validation.constraints.Size; -import java.util.List; - -/** -* Search model for project beneficiary. -*/ - @ApiModel(description = "Search model for project beneficiary.") -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -@Table(name="project_beneficiary") -public class ProjectBeneficiarySearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("tenantId") - @Size(min=2,max=1000) - private String tenantId = null; - - @JsonProperty("projectId") - @Size(min=2,max=64) - private String projectId = null; - - @JsonProperty("beneficiaryId") - @Size(min=2,max=64) - private String beneficiaryId = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; - - @JsonProperty("dateOfRegistration") - private Long dateOfRegistration = null; -} - diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectFacilitySearch.java b/health-services/project/src/main/java/org/egov/project/web/models/ProjectFacilitySearch.java deleted file mode 100644 index 1bba9410e75..00000000000 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectFacilitySearch.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.egov.project.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Table; -import org.springframework.validation.annotation.Validated; - -import java.util.List; - -/** -* This object defines the mapping of a facility to a project. -*/ - @ApiModel(description = "This object defines the mapping of a facility to a project.") -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -@Table(name="project_facility") -public class ProjectFacilitySearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("tenantId") - private String tenantId = null; - - @JsonProperty("facilityId") - private List facilityId = null; - - @JsonProperty("projectId") - private List projectId = null; - -} \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectFacilitySearchRequest.java b/health-services/project/src/main/java/org/egov/project/web/models/ProjectFacilitySearchRequest.java deleted file mode 100644 index 88ca607f150..00000000000 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectFacilitySearchRequest.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.egov.project.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.contract.request.RequestInfo; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -/** -* ProjectFacilitySearchRequest -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectFacilitySearchRequest { - - @JsonProperty("RequestInfo") - @NotNull - @Valid - private RequestInfo requestInfo = null; - - @JsonProperty("ProjectFacility") - @NotNull - @Valid - private ProjectFacilitySearch projectFacility = null; - -} - diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectResourceSearch.java b/health-services/project/src/main/java/org/egov/project/web/models/ProjectResourceSearch.java deleted file mode 100644 index 09e6d1bbaca..00000000000 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectResourceSearch.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.egov.project.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Table; -import org.springframework.validation.annotation.Validated; - -import javax.validation.constraints.Size; -import java.util.List; - -/** -* This object defines the mapping of a resource to a project. -*/ - @ApiModel(description = "This object defines the mapping of a resource to a project.") -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -@Table(name = "project_resource") -public class ProjectResourceSearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("projectId") - @Size(min=2,max=64) - private String projectId = null; - -} - diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectResourceSearchRequest.java b/health-services/project/src/main/java/org/egov/project/web/models/ProjectResourceSearchRequest.java deleted file mode 100644 index 7b62b15d564..00000000000 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectResourceSearchRequest.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.egov.project.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -/** -* ProjectResourceSearchRequest -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectResourceSearchRequest { - - @JsonProperty("RequestInfo") - @NotNull - @Valid - private org.egov.common.contract.request.RequestInfo requestInfo = null; - - @JsonProperty("ProjectResource") - @NotNull - @Valid - private ProjectResourceSearch projectResource = null; - - -} - diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectSearch.java b/health-services/project/src/main/java/org/egov/project/web/models/ProjectSearch.java deleted file mode 100644 index a6ddd479dc5..00000000000 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectSearch.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.egov.project.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Table; -import org.springframework.validation.annotation.Validated; - -import javax.validation.constraints.Size; - -/** -* ProjectSearch -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -@Table(name="project") -public class ProjectSearch { - - @JsonProperty("id") - private String id = null; - - @JsonProperty("tenantId") - private String tenantId = null; - - @JsonProperty("startDate") - private Long startDate = null; - - @JsonProperty("endDate") - private Long endDate = null; - - @JsonProperty("isTaskEnabled") - private Boolean isTaskEnabled = false; - - @JsonProperty("parent") - @Size(min=2,max=64) - private String parent = null; - - @JsonProperty("projectTypeId") - private String projectTypeId = null; - - @JsonProperty("subProjectTypeId") - private String subProjectTypeId = null; - - @JsonProperty("department") - @Size(min=2,max=64) - private String department = null; - - @JsonProperty("referenceId") - @Size(min=2,max=100) - private String referenceId = null; - - @JsonProperty("boundaryCode") - private String boundaryCode = null; - -} - diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectStaffSearch.java b/health-services/project/src/main/java/org/egov/project/web/models/ProjectStaffSearch.java deleted file mode 100644 index d5440bf84d5..00000000000 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectStaffSearch.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.egov.project.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Table; -import org.springframework.validation.annotation.Validated; - -import javax.validation.constraints.Size; -import java.util.List; - -/** -* This object defines the mapping of a system staff user to a project for a certain period. -*/ - @ApiModel(description = "This object defines the mapping of a system staff user to a project for a certain period.") -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -@Table(name="project_staff") -public class ProjectStaffSearch { - - - @JsonProperty("id") - private List id = null; - - @JsonProperty("tenantId") - @Size(min=2,max=1000) - private String tenantId = null; - - @JsonProperty("staffId") - @Size(min=2,max=64) - private String staffId = null; - - @JsonProperty("projectId") - @Size(min=2,max=64) - private String projectId = null; - - @JsonProperty("startDate") - private Long startDate = null; - - @JsonProperty("endDate") - private Long endDate = null; - - -} - diff --git a/health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundaryRequest.java b/health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundaryRequest.java new file mode 100644 index 00000000000..09921ea9493 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundaryRequest.java @@ -0,0 +1,38 @@ +package org.egov.project.web.models.boundary; + +import java.util.List; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryRequest + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @Valid + @NotNull + @JsonProperty("Boundary") + @Size(min = 1, max = 300) + private List boundary = null; + +} diff --git a/health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundaryResponse.java b/health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundaryResponse.java new file mode 100644 index 00000000000..993f24fd8ce --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundaryResponse.java @@ -0,0 +1,44 @@ +package org.egov.project.web.models.boundary; + +import java.util.ArrayList; +import java.util.List; +import jakarta.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryResponse + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Boundary") + @Valid + private List boundary = null; + + + public BoundaryResponse addBoundaryItem(Boundary boundaryItem) { + if (this.boundary == null) { + this.boundary = new ArrayList<>(); + } + this.boundary.add(boundaryItem); + return this; + } + +} diff --git a/health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundarySearchCriteria.java b/health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundarySearchCriteria.java new file mode 100644 index 00000000000..94eaa56c2b3 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundarySearchCriteria.java @@ -0,0 +1,37 @@ +package org.egov.project.web.models.boundary; + +import java.util.List; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundarySearchCriteria { + + @NotNull + @Size(min = 1) + @JsonProperty("codes") + private List codes; + + @NotNull + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} diff --git a/health-services/project/src/main/resources/application.properties b/health-services/project/src/main/resources/application.properties index 22fab270490..93f601466a9 100644 --- a/health-services/project/src/main/resources/application.properties +++ b/health-services/project/src/main/resources/application.properties @@ -68,7 +68,9 @@ kafka.topics.consumer=project-consumer-topic # USER CONFIG egov.user.host=https://dev.digit.org #egov.user.host=http://localhost:8286 +egov.create.user.url=/user/users/_createnovalidate egov.search.user.url=/user/_search +egov.update.user.url=/user/users/_updatenovalidate egov.user.integration.enabled=true # MDMS CONFIG @@ -87,6 +89,10 @@ egov.search.household.url=/household/v1/_search egov.individual.host= egov.search.individual.url= +# use the value as "egov-user" to validate against egov-user service +# use the value as "individual" to validate against individual service +egov.user.id.validator=individual + # FACILITY SERVICE egov.facility.host=http://localhost:8083 egov.search.facility.url=/facility/v1/_search @@ -138,12 +144,12 @@ project.search.max.limit=200 project.management.system.kafka.create.topic=save-project project.management.system.kafka.update.topic=update-project +project.management.system.kafka.update.date.topic=update-project-date -#location config -egov.location.host=https://works-dev.digit.org -egov.location.context.path=/egov-location/location/v11/ -egov.location.endpoint=/boundarys/_search -egov.location.code.query.param=codes +# BOUNDARY SERVICE +egov.boundary.host=http://localhost:8081 +egov.boundary.search.url=/boundary-service/boundary/_search +egov.boundary.hierarchy=HCM-Moz-Hierarchy project.document.id.verification.required=false @@ -157,7 +163,21 @@ project.resource.consumer.bulk.update.topic=update-project-resource-bulk-topic project.resource.consumer.bulk.delete.topic=delete-project-resource-bulk-topic project.mdms.module=HCM-PROJECT-TYPES +task.mdms.module=HCM-TASK-QUANTITY-VALIDATION egov.location.hierarchy.type=ADMIN +#---------Attendance-----------# +project.staff.attendance.topic=project-staff-attendance-health-topic + +#-------Closed Household Task-------# +project.user.action.kafka.create.topic=save-user-action-project-topic +project.user.action.kafka.update.topic=update-user-action-project-topic +project.user.action.consumer.bulk.create.topic=save-user-action-project-bulk-topic +project.user.action.consumer.bulk.update.topic=update-user-action-project-bulk-topic +#-------Location Capture Task-------# +project.location.capture.kafka.create.topic=save-location-capture-project-topic +project.location.capture.consumer.bulk.create.topic=save-location-capture-project-bulk-topic +#---------No resource statuses ------------# +project.task.no.resource.validation.status=ADMINISTRATION_FAILED, BENEFICIARY_REFUSED, CLOSED_HOUSEHOLD, NOT_ADMINISTERED \ No newline at end of file diff --git a/health-services/project/src/main/resources/db/Dockerfile b/health-services/project/src/main/resources/db/Dockerfile index 60fc07ce69f..e7da01d7f0b 100644 --- a/health-services/project/src/main/resources/db/Dockerfile +++ b/health-services/project/src/main/resources/db/Dockerfile @@ -1,4 +1,4 @@ -FROM egovio/flyway:4.1.2 +FROM egovio/flyway:10.7.1 COPY ./migration/main /flyway/sql @@ -6,4 +6,4 @@ COPY migrate.sh /usr/bin/migrate.sh RUN chmod +x /usr/bin/migrate.sh -CMD ["/usr/bin/migrate.sh"] \ No newline at end of file +ENTRYPOINT ["/usr/bin/migrate.sh"] \ No newline at end of file diff --git a/health-services/project/src/main/resources/db/migrate.sh b/health-services/project/src/main/resources/db/migrate.sh index 43960b25cdb..f9d6617822c 100644 --- a/health-services/project/src/main/resources/db/migrate.sh +++ b/health-services/project/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/project/src/main/resources/db/migration/main/V20230517152900__project_address_lat_long_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230517152900__project_address_lat_long_ddl.sql new file mode 100644 index 00000000000..97ac5acb894 --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20230517152900__project_address_lat_long_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE project_address ALTER COLUMN latitude TYPE double precision, ALTER COLUMN longitude TYPE double precision; \ No newline at end of file diff --git a/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql new file mode 100644 index 00000000000..d2b0da3ef3e --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql @@ -0,0 +1,6 @@ +ALTER TABLE PROJECT_TASK ADD COLUMN IF NOT EXISTS clientCreatedTime bigint; +ALTER TABLE PROJECT_TASK ADD COLUMN IF NOT EXISTS clientLastModifiedTime bigint; + +ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN IF NOT EXISTS clientCreatedTime bigint; +ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN IF NOT EXISTS clientLastModifiedTime bigint; + diff --git a/health-services/project/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_project_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_project_ddl.sql new file mode 100644 index 00000000000..bab9c9abdab --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_project_ddl.sql @@ -0,0 +1,5 @@ +ALTER TABLE PROJECT_TASK ADD COLUMN IF NOT EXISTS clientCreatedBy character varying(64); +ALTER TABLE PROJECT_TASK ADD COLUMN IF NOT EXISTS clientLastModifiedBy character varying(64); + +ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN IF NOT EXISTS clientCreatedBy character varying(64); +ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN IF NOT EXISTS clientLastModifiedBy character varying(64); diff --git a/health-services/project/src/main/resources/db/migration/main/V20231026174200__add_tag_project_beneficiary_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20231026174200__add_tag_project_beneficiary_ddl.sql new file mode 100644 index 00000000000..85b2ff465e0 --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20231026174200__add_tag_project_beneficiary_ddl.sql @@ -0,0 +1,3 @@ +ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN IF NOT EXISTS voucherTag character varying(1000); +ALTER TABLE PROJECT_BENEFICIARY ADD UNIQUE (voucherTag); + diff --git a/health-services/project/src/main/resources/db/migration/main/V20231102105200__rename_tag_project_beneficiary_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20231102105200__rename_tag_project_beneficiary_ddl.sql new file mode 100644 index 00000000000..9a268635b56 --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20231102105200__rename_tag_project_beneficiary_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE project_beneficiary RENAME COLUMN voucherTag TO tag; \ No newline at end of file diff --git a/health-services/project/src/main/resources/db/migration/main/V20231121145400__task_resource_quantity_type_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20231121145400__task_resource_quantity_type_ddl.sql new file mode 100644 index 00000000000..d44a32d5b9e --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20231121145400__task_resource_quantity_type_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE task_resource ALTER COLUMN quantity TYPE double precision \ No newline at end of file diff --git a/health-services/project/src/main/resources/db/migration/main/V20231127145800__task_resource_additional_fields_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20231127145800__task_resource_additional_fields_ddl.sql new file mode 100644 index 00000000000..f6e63183775 --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20231127145800__task_resource_additional_fields_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE TASK_RESOURCE ADD COLUMN IF NOT EXISTS additionalDetails jsonb; \ No newline at end of file diff --git a/health-services/project/src/main/resources/db/migration/main/V20240305113500__project_beneficiary_search_index_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20240305113500__project_beneficiary_search_index_ddl.sql new file mode 100644 index 00000000000..bd18dd5bbb5 --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20240305113500__project_beneficiary_search_index_ddl.sql @@ -0,0 +1 @@ +CREATE INDEX IF NOT EXISTS idx_project_beneficiary_beneficiaryClientReferenceId ON project_beneficiary(beneficiaryClientReferenceId); \ No newline at end of file diff --git a/health-services/project/src/main/resources/db/migration/main/V20240305114021__task_resource_search_index_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20240305114021__task_resource_search_index_ddl.sql new file mode 100644 index 00000000000..a4b5a6caf29 --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20240305114021__task_resource_search_index_ddl.sql @@ -0,0 +1 @@ +CREATE INDEX IF NOT EXISTS idx_task_resource_taskid ON task_resource(taskid); \ No newline at end of file diff --git a/health-services/project/src/main/resources/db/migration/main/V20240711175300__user_location_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20240711175300__user_location_ddl.sql new file mode 100644 index 00000000000..fd9a0f8f611 --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20240711175300__user_location_ddl.sql @@ -0,0 +1,23 @@ +CREATE TABLE IF NOT EXISTS USER_LOCATION ( + id CHARACTER VARYING(64), + clientReferenceId CHARACTER VARYING(64), + tenantId CHARACTER VARYING(1000) NOT NULL, + projectId CHARACTER VARYING(64) NOT NULL, + latitude DOUBLE PRECISION NOT NULL, + longitude DOUBLE PRECISION NOT NULL, + locationAccuracy INTEGER NOT NULL, + boundaryCode CHARACTER VARYING(256) NOT NULL, + action CHARACTER VARYING(256), + createdBy CHARACTER VARYING(64) NOT NULL, + createdTime BIGINT NOT NULL, + lastModifiedBy CHARACTER VARYING(64) NOT NULL, + lastModifiedTime BIGINT NOT NULL, + clientCreatedTime BIGINT, + clientLastModifiedTime BIGINT, + clientCreatedBy CHARACTER VARYING(64), + clientLastModifiedBy CHARACTER VARYING(64), + additionalDetails jsonb, + CONSTRAINT pk_user_location PRIMARY KEY (id) +); + +CREATE INDEX IF NOT EXISTS idx_user_location_clientCreatedBy ON USER_LOCATION (clientCreatedBy); diff --git a/health-services/project/src/main/resources/db/migration/main/V20240711175500__user_action_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20240711175500__user_action_ddl.sql new file mode 100644 index 00000000000..411e86e86ef --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20240711175500__user_action_ddl.sql @@ -0,0 +1,28 @@ +CREATE TABLE IF NOT EXISTS USER_ACTION ( +id character varying(64), +clientReferenceId character varying(64), +tenantId character varying(1000) not null, +projectId character varying(64) not null, +latitude double precision not null, +longitude double precision not null, +locationAccuracy INTEGER not null, +boundaryCode CHARACTER VARYING(256) not null, +action CHARACTER VARYING(256) not null, +beneficiaryTag CHARACTER VARYING(64), +resourceTag CHARACTER VARYING(64), +status character varying(1000), +additionalDetails jsonb, +createdBy character varying(64) not null, +createdTime bigint not null, +lastModifiedBy character varying(64) not null, +lastModifiedTime bigint not null, +clientCreatedTime bigint, +clientLastModifiedTime bigint, +clientCreatedBy character varying(64), +clientLastModifiedBy character varying(64), +rowVersion bigint, + CONSTRAINT pk_user_action_id PRIMARY KEY (id), + CONSTRAINT uk_user_action_clientReference_id UNIQUE (clientReferenceId) +); + +CREATE INDEX IF NOT EXISTS idx_user_action_projectId_clientCreatedBy ON USER_ACTION (projectId, clientCreatedBy); diff --git a/health-services/project/src/main/resources/project-indexer.yml b/health-services/project/src/main/resources/project-indexer.yml deleted file mode 100644 index 66f9ee3fe58..00000000000 --- a/health-services/project/src/main/resources/project-indexer.yml +++ /dev/null @@ -1,93 +0,0 @@ -ServiceMaps: - serviceName: Project Service - version: 1.0.0 - mappings: - - topic: save-project-staff-topic - configKey: INDEX - indexes: - - name: projectStaffIndex-v1 - type: projectStaff - id: $.id - isBulk: true - jsonPath: $.* - timeStampField: $.auditDetails.createdTime - - - topic: update-project-staff-topic - configKey: INDEX - indexes: - - name: projectStaffUpdateIndex-v1 - type: projectStaff-update - id: $.id - isBulk: true - jsonPath: $.* - timeStampField: $.auditDetails.lastModifiedTime - - - topic: delete-project-staff-topic - configKey: INDEX - indexes: - - name: projectStaffDeleteIndex-v1 - type: projectStaff-delete - id: $.id - isBulk: true - jsonPath: $.* - timeStampField: $.auditDetails.lastModifiedTime - - - topic: save-project-beneficiary-topic - configKey: INDEX - indexes: - - name: projectBeneficiaryIndex-v1 - type: projectBeneficiary - id: $.id - isBulk: true - jsonPath: $.* - timeStampField: $.auditDetails.createdTime - - - topic: update-project-beneficiary-topic - configKey: INDEX - indexes: - - name: projectBeneficiaryUpdateIndex-v1 - type: projectBeneficiary-update - id: $.id - isBulk: true - jsonPath: $.* - timeStampField: $.auditDetails.lastModifiedTime - - - topic: delete-project-beneficiary-topic - configKey: INDEX - indexes: - - name: projectBeneficiaryDeleteIndex-v1 - type: projectBeneficiary-delete - id: $.id - isBulk: true - jsonPath: $.* - timeStampField: $.auditDetails.lastModifiedTime - - - topic: save-project-facility-topic - configKey: INDEX - indexes: - - name: projectFacilityIndex-v1 - type: projectFacility - id: $.id - isBulk: true - jsonPath: $.* - timeStampField: $.auditDetails.createdTime - - - topic: update-project-facility-topic - configKey: INDEX - indexes: - - name: projectFacilityUpdateIndex-v1 - type: projectFacility-update - id: $.id - isBulk: true - jsonPath: $.* - timeStampField: $.auditDetails.lastModifiedTime - - - topic: delete-project-facility-topic - configKey: INDEX - indexes: - - name: projectFacilityDeleteIndex-v1 - type: projectFacility-delete - id: $.id - isBulk: true - jsonPath: $.* - timeStampField: $.auditDetails.lastModifiedTime \ No newline at end of file diff --git a/health-services/project/src/main/resources/project-persistor.yml b/health-services/project/src/main/resources/project-persistor.yml deleted file mode 100644 index c3b36201e6d..00000000000 --- a/health-services/project/src/main/resources/project-persistor.yml +++ /dev/null @@ -1,555 +0,0 @@ -serviceMaps: - serviceName: project - mappings: - - version: 1.0 - description: Saves a project staff - fromTopic: save-project-staff-topic - isTransaction: true - queryMaps: - - query: INSERT INTO project_staff (id, tenantId, projectId, staffId, startDate, endDate, additionalDetails, createdBy, lastModifiedBy, createdTime, lastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?); - basePath: $.* - jsonMaps: - - jsonPath: $.*.id - - jsonPath: $.*.tenantId - - jsonPath: $.*.projectId - - jsonPath: $.*.userId - - jsonPath: $.*.startDate - - jsonPath: $.*.endDate - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.createdBy - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.createdTime - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - - version: 1.0 - description: Update Project Staff - fromTopic: update-project-staff-topic - isTransaction: true - queryMaps: - - query: UPDATE project_staff SET projectId=?, staffId=?, startDate=?, endDate=?, additionalDetails=?, lastModifiedBy=?, lastModifiedTime=?, rowVersion=?, isDeleted=? WHERE id = ? - basePath: $.* - jsonMaps: - - jsonPath: $.*.projectId - - jsonPath: $.*.userId - - jsonPath: $.*.startDate - - jsonPath: $.*.endDate - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - - version: 1.0 - description: Deletes Project Staff - fromTopic: delete-project-staff-topic - isTransaction: true - queryMaps: - - query: UPDATE project_staff SET lastModifiedBy=?, lastModifiedTime=?, rowVersion=?, isDeleted=? WHERE id=?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - - version: 1.0 - description: Saves a project beneficiary - fromTopic: save-project-beneficiary-topic - isTransaction: true - queryMaps: - - query: INSERT INTO project_beneficiary (id, tenantId, projectId, beneficiaryId, clientReferenceId, beneficiaryClientReferenceId, dateOfRegistration, additionalDetails, createdBy, lastModifiedBy, createdTime, lastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?); - basePath: $.* - jsonMaps: - - jsonPath: $.*.id - - jsonPath: $.*.tenantId - - jsonPath: $.*.projectId - - jsonPath: $.*.beneficiaryId - - jsonPath: $.*.clientReferenceId - - jsonPath: $.*.beneficiaryClientReferenceId - - jsonPath: $.*.dateOfRegistration - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.createdBy - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.createdTime - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - - version: 1.0 - description: Update Project Beneficiary - fromTopic: update-project-beneficiary-topic - isTransaction: true - queryMaps: - - query: UPDATE project_beneficiary SET projectId=?, beneficiaryId=?, clientReferenceId=?, beneficiaryClientReferenceId=?, dateOfRegistration=?, additionalDetails=?, lastModifiedBy=?, lastModifiedTime=?, rowVersion=?, isDeleted=? WHERE id = ? AND isDeleted=false - basePath: $.* - jsonMaps: - - jsonPath: $.*.projectId - - jsonPath: $.*.beneficiaryId - - jsonPath: $.*.clientReferenceId - - jsonPath: $.*.beneficiaryClientReferenceId - - jsonPath: $.*.dateOfRegistration - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - - version: 1.0 - description: Deletes Project Beneficiaries - fromTopic: delete-project-beneficiary-topic - isTransaction: true - queryMaps: - - query: UPDATE project_beneficiary SET lastModifiedBy=?, lastModifiedTime=?, rowVersion=?, isDeleted=? WHERE id=?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - - version: 1.0 - name: Projects - description: Persists project details in project table - fromTopic: save-project - isTransaction: true - queryMaps: - - query: INSERT INTO project(id,tenantId,projectNumber,name,projectType,projectSubType,department,description,referenceId,startDate,endDate,isTaskEnabled,parent,projectHierarchy,additionalDetails,isDeleted,rowVersion,createdBy,lastModifiedBy,createdTime,lastModifiedTime) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); - basePath: $.Projects.* - jsonMaps: - - jsonPath: $.Projects.*.id - - - jsonPath: $.Projects.*.tenantId - - - jsonPath: $.Projects.*.projectNumber - - - jsonPath: $.Projects.*.name - - - jsonPath: $.Projects.*.projectType - - - jsonPath: $.Projects.*.projectSubType - - - jsonPath: $.Projects.*.department - - - jsonPath: $.Projects.*.description - - - jsonPath: $.Projects.*.referenceID - - - jsonPath: $.Projects.*.startDate - - - jsonPath: $.Projects.*.endDate - - - jsonPath: $.Projects.*.isTaskEnabled - - - jsonPath: $.Projects.*.parent - - - jsonPath: $.Projects.*.projectHierarchy - - - jsonPath: $.Projects.*.additionalDetails - type: JSON - dbType: JSONB - - - jsonPath: $.Projects.*.isDeleted - - - jsonPath: $.Projects.*.rowVersion - - - jsonPath: $.Projects.*.auditDetails.createdBy - - - jsonPath: $.Projects.*.auditDetails.lastModifiedBy - - - jsonPath: $.Projects.*.auditDetails.createdTime - - - jsonPath: $.Projects.*.auditDetails.lastModifiedTime - - - - query: INSERT INTO project_address(id,tenantId,projectId,doorNo,latitude,longitude,locationAccuracy,type,addressLine1,addressLine2,landmark,city,pinCode,buildingName,street,locality) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); - basePath: $.Projects.*.address - jsonMaps: - - jsonPath: $.Projects.*.address.id - - - jsonPath: $.Projects.*.address.tenantId - - - jsonPath: $.Projects.*.id - - - jsonPath: $.Projects.*.address.doorNo - - - jsonPath: $.Projects.*.address.latitude - - - jsonPath: $.Projects.*.address.longitude - - - jsonPath: $.Projects.*.address.locationAccuracy - - - jsonPath: $.Projects.*.address.type - - - jsonPath: $.Projects.*.address.addressLine1 - - - jsonPath: $.Projects.*.address.addressLine2 - - - jsonPath: $.Projects.*.address.landmark - - - jsonPath: $.Projects.*.address.city - - - jsonPath: $.Projects.*.address.pincode - - - jsonPath: $.Projects.*.address.buildingName - - - jsonPath: $.Projects.*.address.street - - - jsonPath: $.Projects.*.address.locality - - - - query: INSERT INTO project_target(id,projectId,beneficiaryType,totalNo,targetNo,isDeleted,createdBy,lastModifiedBy,createdTime,lastModifiedTime) VALUES (?,?,?,?,?,?,?,?,?,?); - basePath: $.Projects.*.targets.* - jsonMaps: - - jsonPath: $.Projects.*.targets.*.id - - - jsonPath: $.Projects[*][?({id} in @.targets[*].id)].id - - - jsonPath: $.Projects.*.targets.*.beneficiaryType - - - jsonPath: $.Projects.*.targets.*.totalNo - - - jsonPath: $.Projects.*.targets.*.targetNo - - - jsonPath: $.Projects.*.targets.*.isDeleted - - - jsonPath: $.Projects.*.targets.*.auditDetails.createdBy - - - jsonPath: $.Projects.*.targets.*.auditDetails.lastModifiedBy - - - jsonPath: $.Projects.*.targets.*.auditDetails.createdTime - - - jsonPath: $.Projects.*.targets.*.auditDetails.lastModifiedTime - - - - query: INSERT INTO project_document(id,projectId,documentType,filestoreId,documentUid,additionalDetails,status,createdBy,lastModifiedBy,createdTime,lastModifiedTime) VALUES (?,?,?,?,?,?,?,?,?,?,?); - basePath: $.Projects.*.documents.* - jsonMaps: - - jsonPath: $.Projects.*.documents.*.id - - - jsonPath: $.Projects[*][?({id} in @.documents[*].id)].id - - - jsonPath: $.Projects.*.documents.*.documentType - - - jsonPath: $.Projects.*.documents.*.fileStore - - - jsonPath: $.Projects.*.documents.*.documentUid - - - jsonPath: $.Projects.*.additionalDetails - type: JSON - dbType: JSONB - - - jsonPath: $.Projects.*.documents.*.status - - - jsonPath: $.Projects.*.documents.*.auditDetails.createdBy - - - jsonPath: $.Projects.*.documents.*.auditDetails.lastModifiedBy - - - jsonPath: $.Projects.*.documents.*.auditDetails.createdTime - - - jsonPath: $.Projects.*.documents.*.auditDetails.lastModifiedTime - - - - version: 1.0 - name: Projects - description: Updates project details in project table - fromTopic: update-project - isTransaction: true - queryMaps: - - query: UPDATE project SET name = ?, projectType = ?, projectSubType = ?, department = ?, description = ?, referenceId = ?, startDate = ?, endDate = ?, isTaskEnabled = ?, additionalDetails = ?, isDeleted = ?, rowVersion = ?, lastModifiedBy = ?, lastModifiedTime = ? WHERE id = ?; - basePath: $.Projects.* - jsonMaps: - - - jsonPath: $.Projects.*.name - - - jsonPath: $.Projects.*.projectType - - - jsonPath: $.Projects.*.projectSubType - - - jsonPath: $.Projects.*.department - - - jsonPath: $.Projects.*.description - - - jsonPath: $.Projects.*.referenceID - - - jsonPath: $.Projects.*.startDate - - - jsonPath: $.Projects.*.endDate - - - jsonPath: $.Projects.*.isTaskEnabled - - - jsonPath: $.Projects.*.additionalDetails - type: JSON - dbType: JSONB - - - jsonPath: $.Projects.*.isDeleted - - - jsonPath: $.Projects.*.rowVersion - - - jsonPath: $.Projects.*.auditDetails.lastModifiedBy - - - jsonPath: $.Projects.*.auditDetails.lastModifiedTime - - - jsonPath: $.Projects.*.id - - - - query: UPDATE project_address SET door_no = ?, latitude=?, longitude=?, locationAccuracy=?, type=?, addressLine1=?, addressLine2=?, landmark=?, city=?, pinCode=?, buildingName=?, street=? WHERE id=?; - basePath: $.Projects.*.address - jsonMaps: - - - jsonPath: $.Projects.*.address.doorNo - - - jsonPath: $.Projects.*.address.latitude - - - jsonPath: $.Projects.*.address.longitude - - - jsonPath: $.Projects.*.address.locationAccuracy - - - jsonPath: $.Projects.*.address.type - - - jsonPath: $.Projects.*.address.addressLine1 - - - jsonPath: $.Projects.*.address.addressLine2 - - - jsonPath: $.Projects.*.address.landmark - - - jsonPath: $.Projects.*.address.city - - - jsonPath: $.Projects.*.address.pincode - - - jsonPath: $.Projects.*.address.buildingName - - - jsonPath: $.Projects.*.address.street - - - jsonPath: $.Projects.*.address.id - - - - query: INSERT INTO project_target(id,projectId,beneficiaryType,totalNo,targetNo,isDeleted,createdBy,lastModifiedBy,createdTime,lastModifiedTime) VALUES (?,?,?,?,?,?,?,?,?,?) ON CONFLICT (id) DO UPDATE SET beneficiary_type = ?, totalNo =?, targetNo=?, isDeleted=?, lastModifiedBy=?, lastModifiedTime=?; - basePath: $.Projects.*.targets.* - jsonMaps: - - - jsonPath: $.Projects.*.targets.*.id - - - jsonPath: $.Projects[*][?({id} in @.targets[*].id)].id - - - jsonPath: $.Projects.*.targets.*.beneficiaryType - - - jsonPath: $.Projects.*.targets.*.totalNo - - - jsonPath: $.Projects.*.targets.*.targetNo - - - jsonPath: $.Projects.*.targets.*.isDeleted - - - jsonPath: $.Projects.*.targets.*.auditDetails.createdBy - - - jsonPath: $.Projects.*.targets.*.auditDetails.lastModifiedBy - - - jsonPath: $.Projects.*.targets.*.auditDetails.createdTime - - - jsonPath: $.Projects.*.targets.*.auditDetails.lastModifiedTime - - - jsonPath: $.Projects.*.targets.*.beneficiaryType - - - jsonPath: $.Projects.*.targets.*.totalNo - - - jsonPath: $.Projects.*.targets.*.targetNo - - - jsonPath: $.Projects.*.targets.*.isDeleted - - - jsonPath: $.Projects.*.targets.*.auditDetails.lastModifiedBy - - - jsonPath: $.Projects.*.targets.*.auditDetails.lastModifiedTime - - - - query: INSERT INTO project_document(id,projectId,documentType,filestoreId,documentUid,additionalDetails,status,createdBy,lastModifiedBy,createdTime,lastModifiedTime) VALUES (?,?,?,?,?,?,?,?,?,?,?) ON CONFLICT (id) DO UPDATE SET documentType=?, filestoreId=?, documentUid=?, additionalDetails=?, status=?, lastModifiedBy=?, lastModifiedTime=?; - basePath: $.Projects.*.documents.* - jsonMaps: - - - jsonPath: $.Projects.*.documents.*.id - - - jsonPath: $.Projects[*][?({id} in @.documents[*].id)].id - - - jsonPath: $.Projects.*.documents.*.documentType - - - jsonPath: $.Projects.*.documents.*.fileStore - - - jsonPath: $.Projects.*.documents.*.documentUid - - - jsonPath: $.Projects.*.additionalDetails - type: JSON - dbType: JSONB - - - jsonPath: $.Projects.*.documents.*.status - - - jsonPath: $.Projects.*.documents.*.auditDetails.createdBy - - - jsonPath: $.Projects.*.documents.*.auditDetails.lastModifiedBy - - - jsonPath: $.Projects.*.documents.*.auditDetails.createdTime - - - jsonPath: $.Projects.*.documents.*.auditDetails.lastModifiedTime - - - jsonPath: $.Projects.*.documents.*.documentType - - - jsonPath: $.Projects.*.documents.*.fileStore - - - jsonPath: $.Projects.*.documents.*.documentUid - - - jsonPath: $.Projects.*.additionalDetails - type: JSON - dbType: JSONB - - - jsonPath: $.Projects.*.documents.*.status - - - jsonPath: $.Projects.*.documents.*.auditDetails.lastModifiedBy - - - jsonPath: $.Projects.*.documents.*.auditDetails.lastModifiedTime - - - version: 1.0 - description: Saves a project resourcce - fromTopic: save-project-resource-topic - isTransaction: true - queryMaps: - - query: INSERT INTO project_resource (id, tenantId, projectId, productVariantId, isBaseUnitVariant, startDate, endDate, additionalDetails, createdBy, lastModifiedBy, createdTime, lastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?); - basePath: $.* - jsonMaps: - - jsonPath: $.*.id - - jsonPath: $.*.tenantId - - jsonPath: $.*.projectId - - jsonPath: $.*.productVariantId - - jsonPath: $.*.isBaseUnitVariant - - jsonPath: $.*.startDate - - jsonPath: $.*.endDate - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.createdBy - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.createdTime - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - - version: 1.0 - description: Update a project resourcce - fromTopic: update-project-resource-topic - isTransaction: true - queryMaps: - - query: UPDATE project_resource SET tenantId=?, projectId=?, productVariantId=?, isBaseUnitVariant=?, startDate=?, endDate=?, additionalDetails=?, lastModifiedBy=?, lastModifiedTime=?, rowVersion=?, isDeleted=? WHERE id = ? - basePath: $.* - jsonMaps: - - jsonPath: $.*.tenantId - - jsonPath: $.*.projectId - - jsonPath: $.*.productVariantId - - jsonPath: $.*.isBaseUnitVariant - - jsonPath: $.*.startDate - - jsonPath: $.*.endDate - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - - version: 1.0 - description: Delete a project resourcce - fromTopic: delete-project-resource-topic - isTransaction: true - queryMaps: - - query: UPDATE project_resource SET lastModifiedBy=?, lastModifiedTime=?, rowVersion=?, isDeleted=? WHERE id = ? - basePath: $.* - jsonMaps: - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - - version: 1.0 - description: Saves a project facility - fromTopic: save-project-facility-topic - isTransaction: true - queryMaps: - - - query: INSERT INTO project_facility (id, tenantId, projectId, facilityId, additionalDetails, createdBy, lastModifiedBy, createdTime, lastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?); - basePath: $.* - jsonMaps: - - jsonPath: $.*.id - - - jsonPath: $.*.tenantId - - - jsonPath: $.*.projectId - - - jsonPath: $.*.facilityId - - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - - jsonPath: $.*.auditDetails.createdBy - - - jsonPath: $.*.auditDetails.lastModifiedBy - - - jsonPath: $.*.auditDetails.createdTime - - - jsonPath: $.*.auditDetails.lastModifiedTime - - - jsonPath: $.*.rowVersion - - - jsonPath: $.*.isDeleted - - - version: 1.0 - description: Update Project Facility - fromTopic: update-project-facility-topic - isTransaction: true - queryMaps: - - - query: UPDATE project_facility SET projectId=?, facilityId=?, additionalDetails=?, lastModifiedBy=?, lastModifiedTime=?, rowVersion=?, isDeleted=? WHERE id = ? - basePath: $.* - jsonMaps: - - jsonPath: $.*.projectId - - - jsonPath: $.*.facilityId - - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - - jsonPath: $.*.auditDetails.lastModifiedBy - - - jsonPath: $.*.auditDetails.lastModifiedTime - - - jsonPath: $.*.rowVersion - - - jsonPath: $.*.isDeleted - - - jsonPath: $.*.id - - - version: 1.0 - description: Deletes Project Facility - fromTopic: delete-project-facility-topic - isTransaction: true - queryMaps: - - query: UPDATE project_facility SET lastModifiedBy=?, lastModifiedTime=?, rowVersion=?, isDeleted=? WHERE id=?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id \ No newline at end of file diff --git a/health-services/project/src/main/resources/project-task-persister.yml b/health-services/project/src/main/resources/project-task-persister.yml deleted file mode 100644 index e8e2a62dcd5..00000000000 --- a/health-services/project/src/main/resources/project-task-persister.yml +++ /dev/null @@ -1,158 +0,0 @@ -serviceMaps: - serviceName: project - mappings: - - version: 1.0 - description: Saves a project task - fromTopic: save-project-task-topic - isTransaction: true - queryMaps: - - query: INSERT INTO PROJECT_TASK(id, clientReferenceId, tenantId, projectId, projectBeneficiaryId, projectBeneficiaryClientReferenceId, plannedStartDate, plannedEndDate, actualStartDate, actualEndDate, addressId, status, additionalDetails, createdBy, createdTime, lastModifiedBy, lastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); - basePath: $.* - jsonMaps: - - jsonPath: $.*.id - - jsonPath: $.*.clientReferenceId - - jsonPath: $.*.tenantId - - jsonPath: $.*.projectId - - jsonPath: $.*.projectBeneficiaryId - - jsonPath: $.*.projectBeneficiaryClientReferenceId - - jsonPath: $.*.plannedStartDate - - jsonPath: $.*.plannedEndDate - - jsonPath: $.*.actualStartDate - - jsonPath: $.*.actualEndDate - - jsonPath: $.*.address.id - - jsonPath: $.*.status - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.createdBy - - jsonPath: $.*.auditDetails.createdTime - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - - query: INSERT INTO ADDRESS(id, tenantid, doorno, latitude, longitude, locationAccuracy, type, addressline1, addressline2, landmark, city, pincode, buildingName, street, localityCode) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); - basePath: $.*.address - jsonMaps: - - jsonPath: $.*.address.id - - jsonPath: $.*.address.tenantId - - jsonPath: $.*.address.doorNo - - jsonPath: $.*.address.latitude - - jsonPath: $.*.address.longitude - - jsonPath: $.*.address.locationAccuracy - - jsonPath: $.*.address.type - - jsonPath: $.*.address.addressLine1 - - jsonPath: $.*.address.addressLine2 - - jsonPath: $.*.address.landmark - - jsonPath: $.*.address.city - - jsonPath: $.*.address.pincode - - jsonPath: $.*.address.buildingName - - jsonPath: $.*.address.street - - jsonPath: $.*.address.locality.code - - - query: INSERT INTO TASK_RESOURCE(id, tenantid, productvariantid, taskid, quantity, isDelivered, reasonIfNotDelivered, createdBy, createdTime, lastModifiedBy, lastModifiedTime, isDeleted) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); - basePath: $.*.resources.* - jsonMaps: - - jsonPath: $.*.resources.*.id - - jsonPath: $.*.resources.*.tenantId - - jsonPath: $.*.resources.*.productVariantId - - jsonPath: $.*.resources.*.taskId - - jsonPath: $.*.resources.*.quantity - - jsonPath: $.*.resources.*.isDelivered - - jsonPath: $.*.resources.*.deliveryComment - - jsonPath: $.*.resources.*.auditDetails.createdBy - - jsonPath: $.*.resources.*.auditDetails.createdTime - - jsonPath: $.*.resources.*.auditDetails.lastModifiedBy - - jsonPath: $.*.resources.*.auditDetails.lastModifiedTime - - jsonPath: $.*.resources.*.isDeleted - - - version: 1.0 - description: Updates a project task - fromTopic: update-project-task-topic - isTransaction: true - queryMaps: - - query: UPDATE PROJECT_TASK SET tenantId = ?, projectId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, addressId = ?, plannedStartDate = ?, plannedEndDate = ?, actualStartDate = ?, actualEndDate = ?, status = ?, additionalDetails = ?, lastModifiedBy = ?, lastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.tenantId - - jsonPath: $.*.projectId - - jsonPath: $.*.projectBeneficiaryId - - jsonPath: $.*.projectBeneficiaryClientReferenceId - - jsonPath: $.*.address.id - - jsonPath: $.*.plannedStartDate - - jsonPath: $.*.plannedEndDate - - jsonPath: $.*.actualStartDate - - jsonPath: $.*.actualEndDate - - jsonPath: $.*.status - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - - query: UPDATE ADDRESS SET tenantId = ?, doorno = ?, latitude = ?, longitude = ?, locationAccuracy = ?, type = ?, addressline1 = ?, addressline2 = ?, landmark = ?, city = ?, pincode = ?, buildingName = ?, street = ?, localityCode = ? WHERE ID = ?; - basePath: $.*.address - jsonMaps: - - jsonPath: $.*.address.tenantId - - jsonPath: $.*.address.doorNo - - jsonPath: $.*.address.latitude - - jsonPath: $.*.address.longitude - - jsonPath: $.*.address.locationAccuracy - - jsonPath: $.*.address.type - - jsonPath: $.*.address.addressLine1 - - jsonPath: $.*.address.addressLine2 - - jsonPath: $.*.address.landmark - - jsonPath: $.*.address.city - - jsonPath: $.*.address.pincode - - jsonPath: $.*.address.buildingName - - jsonPath: $.*.address.street - - jsonPath: $.*.address.locality.code - - jsonPath: $.*.address.id - - - query: INSERT INTO TASK_RESOURCE(id, tenantid, productvariantid, taskid, quantity, isDelivered, reasonIfNotDelivered, createdBy, createdTime, lastModifiedBy, lastModifiedTime, isDeleted) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (id) DO UPDATE SET tenantid = ?, taskid = ?, productvariantid = ?, quantity = ?, isDelivered = ?, reasonIfNotDelivered = ?, lastModifiedBy = ?, lastModifiedTime = ?; - basePath: $.*.resources.* - jsonMaps: - - jsonPath: $.*.resources.*.id - - jsonPath: $.*.resources.*.tenantId - - jsonPath: $.*.resources.*.productVariantId - - jsonPath: $.*.resources.*.taskId - - jsonPath: $.*.resources.*.quantity - - jsonPath: $.*.resources.*.isDelivered - - jsonPath: $.*.resources.*.deliveryComment - - jsonPath: $.*.resources.*.auditDetails.createdBy - - jsonPath: $.*.resources.*.auditDetails.createdTime - - jsonPath: $.*.resources.*.auditDetails.lastModifiedBy - - jsonPath: $.*.resources.*.auditDetails.lastModifiedTime - - jsonPath: $.*.resources.*.isDeleted - - jsonPath: $.*.resources.*.tenantId - - jsonPath: $.*.resources.*.productVariantId - - jsonPath: $.*.resources.*.taskId - - jsonPath: $.*.resources.*.quantity - - jsonPath: $.*.resources.*.isDelivered - - jsonPath: $.*.resources.*.deliveryComment - - jsonPath: $.*.resources.*.auditDetails.lastModifiedBy - - jsonPath: $.*.resources.*.auditDetails.lastModifiedTime - - - version: 1.0 - description: Deletes a project task - fromTopic: delete-project-task-topic - isTransaction: true - queryMaps: - - query: UPDATE PROJECT_TASK SET lastModifiedBy = ?, lastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - query: UPDATE TASK_RESOURCE SET lastModifiedBy = ?, lastModifiedTime = ?, isDeleted = ? WHERE ID = ?; - basePath: $.*.resources.* - jsonMaps: - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id \ No newline at end of file diff --git a/health-services/project/src/test/java/org/egov/project/helper/ProjectBeneficiaryTestBuilder.java b/health-services/project/src/test/java/org/egov/project/helper/ProjectBeneficiaryTestBuilder.java index 13f2b0a38e9..540018a7a95 100644 --- a/health-services/project/src/test/java/org/egov/project/helper/ProjectBeneficiaryTestBuilder.java +++ b/health-services/project/src/test/java/org/egov/project/helper/ProjectBeneficiaryTestBuilder.java @@ -1,16 +1,16 @@ package org.egov.project.helper; import org.egov.common.helper.AuditDetailsTestBuilder; -import org.egov.common.models.project.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectBeneficiary; public class ProjectBeneficiaryTestBuilder { - private ProjectBeneficiary.ProjectBeneficiaryBuilder builder; + private ProjectBeneficiary.ProjectBeneficiaryBuilder builder; public ProjectBeneficiaryTestBuilder() { - this.builder = ProjectBeneficiary.builder(); + this.builder = (ProjectBeneficiary.ProjectBeneficiaryBuilder) ProjectBeneficiary.builder(); } public static ProjectBeneficiaryTestBuilder builder() { @@ -18,25 +18,27 @@ public static ProjectBeneficiaryTestBuilder builder() { } public ProjectBeneficiary build() { - return this.builder.hasErrors(false).build(); + return this.builder.hasErrors(Boolean.FALSE).build(); } public ProjectBeneficiaryTestBuilder withIdNull() { this.builder.projectId("some-project-id") + .beneficiaryId("beneficiary-id") + .dateOfRegistration(Long.valueOf(1673577580L)) .clientReferenceId("beneficiaryClientReferenceId") .id(null) - .beneficiaryId("beneficiary-id") - .dateOfRegistration(1673577580L) .tenantId("some-tenant-id") - .rowVersion(1); + .rowVersion(Integer.valueOf(1)); return this; } public ProjectBeneficiaryTestBuilder withId() { - withIdNull().builder.id("some-id").beneficiaryId("beneficiary-id") - .dateOfRegistration(1673577580L) + withIdNull().builder + .beneficiaryId("beneficiary-id") + .dateOfRegistration(Long.valueOf(1673577580L)) .projectId("some-project-id") .clientReferenceId("beneficiaryClientReferenceId") + .id("some-id") .tenantId("some-tenant-id"); return this; } @@ -55,9 +57,9 @@ public ProjectBeneficiaryTestBuilder goodProjectBeneficiary() { this.builder.projectId("some-project-id") .beneficiaryId("beneficiary-id") .clientReferenceId("beneficiaryClientReferenceId") - .dateOfRegistration(1673577580L) + .dateOfRegistration(Long.valueOf(1673577580L)) .tenantId("some-tenant-id") - .rowVersion(1) + .rowVersion(Integer.valueOf(1)) .additionalFields(AdditionalFields.builder().build()) .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); return this; @@ -69,7 +71,7 @@ public ProjectBeneficiaryTestBuilder withAuditDetails() { } public ProjectBeneficiaryTestBuilder withDeleted() { - this.builder.isDeleted(true); + this.builder.isDeleted(Boolean.TRUE); return this; } } diff --git a/health-services/project/src/test/java/org/egov/project/helper/ProjectFacilityTestBuilder.java b/health-services/project/src/test/java/org/egov/project/helper/ProjectFacilityTestBuilder.java index 07380c1f025..b14aa21e008 100644 --- a/health-services/project/src/test/java/org/egov/project/helper/ProjectFacilityTestBuilder.java +++ b/health-services/project/src/test/java/org/egov/project/helper/ProjectFacilityTestBuilder.java @@ -1,16 +1,16 @@ package org.egov.project.helper; import org.egov.common.helper.AuditDetailsTestBuilder; -import org.egov.common.models.project.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectFacility; public class ProjectFacilityTestBuilder { - private ProjectFacility.ProjectFacilityBuilder builder; + private ProjectFacility.ProjectFacilityBuilder builder; public ProjectFacilityTestBuilder() { - this.builder = ProjectFacility.builder(); + this.builder = (ProjectFacility.ProjectFacilityBuilder) ProjectFacility.builder(); } public static ProjectFacilityTestBuilder builder() { @@ -33,7 +33,9 @@ public ProjectFacilityTestBuilder withIdNull() { } public ProjectFacilityTestBuilder withId() { - withIdNull().builder.id("some-id").facilityId("facility-id"); + withIdNull().builder + .facilityId("facility-id") + .id("some-id"); return this; } diff --git a/health-services/project/src/test/java/org/egov/project/helper/ProjectResourceTestBuilder.java b/health-services/project/src/test/java/org/egov/project/helper/ProjectResourceTestBuilder.java index 36589d22399..00d904d7cfd 100644 --- a/health-services/project/src/test/java/org/egov/project/helper/ProjectResourceTestBuilder.java +++ b/health-services/project/src/test/java/org/egov/project/helper/ProjectResourceTestBuilder.java @@ -7,10 +7,10 @@ public class ProjectResourceTestBuilder { - private final ProjectResource.ProjectResourceBuilder builder; + private final ProjectResource.ProjectResourceBuilder builder; public ProjectResourceTestBuilder() { - this.builder = ProjectResource.builder(); + this.builder = (ProjectResource.ProjectResourceBuilder) ProjectResource.builder(); } public static ProjectResourceTestBuilder builder() { diff --git a/health-services/project/src/test/java/org/egov/project/helper/ProjectStaffTestBuilder.java b/health-services/project/src/test/java/org/egov/project/helper/ProjectStaffTestBuilder.java index 4e7437a0ff3..21d5fe001f9 100644 --- a/health-services/project/src/test/java/org/egov/project/helper/ProjectStaffTestBuilder.java +++ b/health-services/project/src/test/java/org/egov/project/helper/ProjectStaffTestBuilder.java @@ -1,16 +1,16 @@ package org.egov.project.helper; import org.egov.common.helper.AuditDetailsTestBuilder; -import org.egov.common.models.project.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectStaff; public class ProjectStaffTestBuilder { - private ProjectStaff.ProjectStaffBuilder builder; + private ProjectStaff.ProjectStaffBuilder builder; public ProjectStaffTestBuilder() { - this.builder = ProjectStaff.builder(); + this.builder = (ProjectStaff.ProjectStaffBuilder) ProjectStaff.builder(); } public static ProjectStaffTestBuilder builder() { diff --git a/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java b/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java index 95a7fb2c3b7..453e3be4d11 100644 --- a/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java +++ b/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java @@ -1,17 +1,18 @@ package org.egov.project.helper; +import java.util.Arrays; + import org.egov.common.helper.AuditDetailsTestBuilder; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskResource; - -import java.util.Arrays; +import org.egov.common.models.project.TaskStatus; public class TaskTestBuilder { - private final Task.TaskBuilder builder; + private final Task.TaskBuilder builder; public TaskTestBuilder() { - this.builder = Task.builder(); + this.builder = (Task.TaskBuilder) Task.builder(); } public static TaskTestBuilder builder() { @@ -23,19 +24,23 @@ public Task build() { } public TaskTestBuilder withTask() { - this.builder.id("some-id").actualEndDate(100L).actualStartDate(100L) - .hasErrors(Boolean.FALSE) - .tenantId("default") + this.builder.actualEndDate(100L).actualStartDate(100L) .plannedStartDate(100L).plannedEndDate(101L) - .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()) .address(AddressTestBuilder.builder().withAddress().build()) .resources(Arrays.asList(TaskResource.builder().tenantId("default").isDelivered(false) - .quantity(100L).productVariantId("v101").build(), + .quantity(100.0).productVariantId("v101").build(), TaskResource.builder().tenantId("default").isDelivered(false) - .quantity(100L).productVariantId("v101").build())) - .isDeleted(false).rowVersion(0).projectBeneficiaryId("some-id") + .quantity(100.0).productVariantId("v101").build())) .projectId("some-id").createdBy("some-id") - .createdDate(100L).status("status").build(); + .createdDate(100L) + .status(TaskStatus.DELIVERED) + .isDeleted(false).projectBeneficiaryId("some-id") + .rowVersion(0) + .hasErrors(Boolean.FALSE) + .tenantId("default") + .id("some-id") + .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()) + .build(); return this; } } diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryEnrichmentServiceUpdateTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryEnrichmentServiceUpdateTest.java index 4d4abb69acf..fe4d3b9e597 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryEnrichmentServiceUpdateTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryEnrichmentServiceUpdateTest.java @@ -1,5 +1,6 @@ package org.egov.project.service; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.BeneficiaryBulkRequest; import org.egov.common.models.project.ProjectBeneficiary; import org.egov.common.service.IdGenService; @@ -66,9 +67,9 @@ void setUp() throws Exception { private void mockFindById() { lenient().when(projectBeneficiaryRepository.findById( eq(projectBeneficiaryIds), - eq(false), - anyString()) - ).thenReturn(request.getProjectBeneficiaries()); + anyString(), + eq(false)) + ).thenReturn(SearchResponse.builder().response(request.getProjectBeneficiaries()).build()); } @Test @@ -98,7 +99,7 @@ void shouldUpdateTheRowVersionInTheResult() throws Exception { void shouldFetchExistingRecordsUsingId() throws Exception { mockFindById(); projectBeneficiaryEnrichmentService.update(request.getProjectBeneficiaries(), request); - verify(projectBeneficiaryRepository, times(1)).findById(anyList(), eq(false), anyString()); + verify(projectBeneficiaryRepository, times(1)).findById(anyList(), anyString(), eq(false)); } @Test diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceSearchTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceSearchTest.java index 6744e51ba7d..89caae1f1d0 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceSearchTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceSearchTest.java @@ -2,11 +2,12 @@ import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectBeneficiary; import org.egov.project.helper.ProjectBeneficiaryTestBuilder; import org.egov.project.repository.ProjectBeneficiaryRepository; -import org.egov.project.web.models.BeneficiarySearchRequest; -import org.egov.project.web.models.ProjectBeneficiarySearch; +import org.egov.common.models.project.BeneficiarySearchRequest; +import org.egov.common.models.project.ProjectBeneficiarySearch; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -49,9 +50,9 @@ void setUp() throws QueryBuilderException { @DisplayName("should not raise exception if no search results are found") void shouldNotRaiseExceptionIfNoProjectBeneficiaryFound() throws Exception { when(projectBeneficiaryRepository.find(any(ProjectBeneficiarySearch.class), any(Integer.class), - any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(Collections.emptyList()); + any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(SearchResponse.builder().build()); ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() - .id(Collections.singletonList("ID101")).projectId("some-id").build(); + .id(Collections.singletonList("ID101")).projectId(Collections.singletonList("some-id")).build(); BeneficiarySearchRequest beneficiarySearchRequest = BeneficiarySearchRequest.builder() .projectBeneficiary(projectBeneficiarySearch).requestInfo(RequestInfoTestBuilder.builder() .withCompleteRequestInfo().build()).build(); @@ -64,17 +65,17 @@ void shouldNotRaiseExceptionIfNoProjectBeneficiaryFound() throws Exception { @DisplayName("should return project beneficiary if search criteria is matched") void shouldReturnProjectStaffIfSearchCriteriaIsMatched() throws Exception { when(projectBeneficiaryRepository.find(any(ProjectBeneficiarySearch.class), any(Integer.class), - any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(projectBeneficiary); + any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(SearchResponse.builder().response(projectBeneficiary).build()); projectBeneficiary.add(ProjectBeneficiaryTestBuilder.builder().withId().withId().withAuditDetails().build()); ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() - .id(Collections.singletonList("ID101")).projectId("some-projectId").build(); + .id(Collections.singletonList("ID101")).projectId(Collections.singletonList("some-projectId")).build(); BeneficiarySearchRequest beneficiarySearchRequest = BeneficiarySearchRequest.builder() .projectBeneficiary(projectBeneficiarySearch).requestInfo(RequestInfoTestBuilder.builder() .withCompleteRequestInfo().build()).build(); - List projectStaffs = projectBeneficiaryService.search(beneficiarySearchRequest, 10, 0, "default", null, false); + List projectBeneficiaries = projectBeneficiaryService.search(beneficiarySearchRequest, 10, 0, "default", null, false).getResponse(); - assertEquals(1, projectStaffs.size()); + assertEquals(1, projectBeneficiaries.size()); } @Test @@ -86,10 +87,10 @@ void shouldReturnFromCacheIfSearchCriteriaHasIdOnly() throws Exception { BeneficiarySearchRequest projectStaffSearchRequest = BeneficiarySearchRequest.builder() .projectBeneficiary(projectBeneficiarySearch).requestInfo(RequestInfoTestBuilder.builder() .withCompleteRequestInfo().build()).build(); - when(projectBeneficiaryRepository.findById(anyList(), anyBoolean(), anyString())).thenReturn(projectBeneficiary); + when(projectBeneficiaryRepository.findById(anyList(), anyString(), anyBoolean())).thenReturn(SearchResponse.builder().response(projectBeneficiary).build()); List projectBeneficiaries = projectBeneficiaryService.search(projectStaffSearchRequest, - 10, 0, null, null, true); + 10, 0, null, null, true).getResponse(); assertEquals(1, projectBeneficiaries.size()); } diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceUpdateTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceUpdateTest.java index ecd674abd25..805fba5c474 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceUpdateTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceUpdateTest.java @@ -5,6 +5,7 @@ import digit.models.coremodels.mdms.MdmsCriteriaReq; import org.apache.commons.io.IOUtils; import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdBulkResponse; import org.egov.common.models.household.HouseholdSearchRequest; @@ -158,9 +159,9 @@ private void mockValidateBeneficiarytId() { private void mockFindById() { lenient().when(projectBeneficiaryRepository.findById( eq(projectBeneficiaryIds), - eq(false), - anyString()) - ).thenReturn(request.getProjectBeneficiaries()); + anyString(), + eq(false)) + ).thenReturn(SearchResponse.builder().response(request.getProjectBeneficiaries()).build()); } private void mockMdms(String responseFileName) throws Exception { @@ -208,7 +209,7 @@ void shouldThrowExceptionIfFetchedRecordsCountDoesntMatchTheCountInRequest() thr mockServiceRequestClient(); mockMdms(HOUSEHOLD_RESPONSE_FILE_NAME); mockProjectFindIds(); - when(projectBeneficiaryRepository.findById(anyList(), eq(false), anyString())).thenReturn(Collections.emptyList()); + when(projectBeneficiaryRepository.findById(anyList(), anyString(), eq(false))).thenReturn(SearchResponse.builder().build()); assertThrows(CustomException.class, () -> projectBeneficiaryService.update(request, false)); } diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectFacilityServiceSearchTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectFacilityServiceSearchTest.java index 067d9e58f31..6eed8465ca5 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectFacilityServiceSearchTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectFacilityServiceSearchTest.java @@ -4,8 +4,8 @@ import org.egov.common.models.project.ProjectFacility; import org.egov.project.helper.ProjectFacilityTestBuilder; import org.egov.project.repository.ProjectFacilityRepository; -import org.egov.project.web.models.ProjectFacilitySearch; -import org.egov.project.web.models.ProjectFacilitySearchRequest; +import org.egov.common.models.project.ProjectFacilitySearch; +import org.egov.common.models.project.ProjectFacilitySearchRequest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java index 5f8a6461f88..36aa7100f8d 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java @@ -4,8 +4,8 @@ import org.egov.common.models.project.ProjectStaff; import org.egov.project.helper.ProjectStaffTestBuilder; import org.egov.project.repository.ProjectStaffRepository; -import org.egov.project.web.models.ProjectStaffSearch; -import org.egov.project.web.models.ProjectStaffSearchRequest; +import org.egov.common.models.project.ProjectStaffSearch; +import org.egov.common.models.project.ProjectStaffSearchRequest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -50,7 +50,7 @@ void shouldNotRaiseExceptionIfNoProjectStaffFound() throws Exception { any(Integer.class), any(String.class), eq(null), any(Boolean.class))) .thenReturn(Collections.emptyList()); ProjectStaffSearch projectStaffSearch = ProjectStaffSearch.builder() - .id(Collections.singletonList("ID101")).staffId("some-user-id").build(); + .id(Collections.singletonList("ID101")).staffId(Collections.singletonList("some-user-id")).build(); ProjectStaffSearchRequest projectStaffSearchRequest = ProjectStaffSearchRequest.builder() .projectStaff(projectStaffSearch).requestInfo(RequestInfoTestBuilder.builder() .withCompleteRequestInfo().build()).build(); @@ -78,7 +78,7 @@ void shouldReturnProjectStaffIfSearchCriteriaIsMatched() throws Exception { when(projectStaffRepository.find(any(ProjectStaffSearch.class), any(Integer.class), any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(projectStaffs); projectStaffs.add(ProjectStaffTestBuilder.builder().withId().withId().withAuditDetails().build()); - ProjectStaffSearch projectStaffSearch = ProjectStaffSearch.builder().id(Collections.singletonList("ID101")).projectId("some-projectId").build(); + ProjectStaffSearch projectStaffSearch = ProjectStaffSearch.builder().id(Collections.singletonList("ID101")).projectId(Collections.singletonList("some-projectId")).build(); ProjectStaffSearchRequest projectStaffSearchRequest = ProjectStaffSearchRequest.builder() .projectStaff(projectStaffSearch).requestInfo(RequestInfoTestBuilder.builder() .withCompleteRequestInfo().build()).build(); diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectTaskServiceSearchTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectTaskServiceSearchTest.java index b81d80be1f3..418f9321695 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectTaskServiceSearchTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectTaskServiceSearchTest.java @@ -2,6 +2,7 @@ import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskSearch; import org.egov.common.models.project.TaskSearchRequest; @@ -55,7 +56,7 @@ void shouldOnlySearchByIdIfOnlyIdIsPresent() { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .task(TaskSearch.builder().id(Collections.singletonList("some-id")).build()).build(); when(projectTaskRepository.findById(anyList(), eq("id"), anyBoolean())) - .thenReturn(Collections.emptyList()); + .thenReturn(SearchResponse.builder().build()); projectTaskService.search(taskSearchRequest.getTask(), 10, 0, "default", null, false); @@ -71,7 +72,7 @@ void shouldOnlySearchByClientReferenceIdIfOnlyClientReferenceIdIsPresent() { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .task(TaskSearch.builder().clientReferenceId(Collections.singletonList("some-id")).build()).build(); when(projectTaskRepository.findById(anyList(), eq("clientReferenceId"), anyBoolean())) - .thenReturn(Collections.emptyList()); + .thenReturn(SearchResponse.builder().build()); projectTaskService.search(taskSearchRequest.getTask(), 10, 0, "default", null, false); @@ -87,7 +88,7 @@ void shouldNotCallFindByIfIfMoreParametersAreAvailable() throws QueryBuilderExce .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .task(TaskSearch.builder().id(Collections.singletonList("some-id")).clientReferenceId(Collections.singletonList("some-id")).build()).build(); when(projectTaskRepository.find(any(TaskSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(SearchResponse.builder().build()); projectTaskService.search(taskSearchRequest.getTask(), 10, 0, "default", 0L, false); @@ -103,7 +104,7 @@ void shouldCallFindIfMoreParametersAreAvailable() throws QueryBuilderException { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .task(TaskSearch.builder().id(Collections.singletonList("some-id")).clientReferenceId(Collections.singletonList("some-id")).build()).build(); when(projectTaskRepository.find(any(TaskSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(SearchResponse.builder().build()); projectTaskService.search(taskSearchRequest.getTask(), 10, 0, "default", 0L, false); @@ -117,7 +118,7 @@ void shouldCallFindIfMoreParametersAreAvailable() throws QueryBuilderException { @DisplayName("should not raise exception if no search results are found") void shouldNotRaiseExceptionIfNoProjectTaskFound() throws Exception { when(projectTaskRepository.find(any(TaskSearch.class), any(Integer.class), - any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(Collections.emptyList()); + any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(SearchResponse.builder().build()); TaskSearchRequest taskSearchRequest = TaskSearchRequest.builder() .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .task(TaskSearch.builder().id(Collections.singletonList("someid")).clientReferenceId(Collections.singletonList("some-id")).build()).build(); @@ -130,7 +131,7 @@ void shouldNotRaiseExceptionIfNoProjectTaskFound() throws Exception { @Test @DisplayName("should not raise exception if no search results are found for search by id") void shouldNotRaiseExceptionIfNoProjectTaskFoundForSearchById() throws Exception { - when(projectTaskRepository.findById(anyList(), anyString(), anyBoolean())).thenReturn(Collections.emptyList()); + when(projectTaskRepository.findById(anyList(), anyString(), anyBoolean())).thenReturn(SearchResponse.builder().build()); TaskSearchRequest taskSearchRequest = TaskSearchRequest.builder() .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .task(TaskSearch.builder().id(Collections.singletonList("some-id")).build()).build(); @@ -144,13 +145,13 @@ void shouldNotRaiseExceptionIfNoProjectTaskFoundForSearchById() throws Exception void shouldReturnProjectStaffIfSearchCriteriaIsMatched() throws Exception { projectTasks.add(TaskTestBuilder.builder().withTask().build()); when(projectTaskRepository.find(any(TaskSearch.class), any(Integer.class), - any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(projectTasks); + any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(SearchResponse.builder().response(projectTasks).build()); TaskSearchRequest taskSearchRequest = TaskSearchRequest.builder() .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) - .task(TaskSearch.builder().id(Collections.singletonList("some-id")).projectId("some-id").build()).build(); + .task(TaskSearch.builder().id(Collections.singletonList("some-id")).projectId(Collections.singletonList("some-id")).build()).build(); List projectTasks = projectTaskService.search(taskSearchRequest.getTask(), 10, 0, - "default", null, false); + "default", null, false).getResponse(); assertEquals(1, projectTasks.size()); } @@ -159,13 +160,13 @@ void shouldReturnProjectStaffIfSearchCriteriaIsMatched() throws Exception { @DisplayName("should return from find by id if search criteria has id only") void shouldReturnFromFindByIdIfSearchCriteriaHasIdOnly() throws Exception { projectTasks.add(TaskTestBuilder.builder().withTask().build()); - when(projectTaskRepository.findById(anyList(), anyString(), anyBoolean())).thenReturn(projectTasks); + when(projectTaskRepository.findById(anyList(), anyString(), anyBoolean())).thenReturn(SearchResponse.builder().response(projectTasks).build()); TaskSearchRequest taskSearchRequest = TaskSearchRequest.builder() .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .task(TaskSearch.builder().id(Collections.singletonList("some-id")).build()).build(); List projectTasks = projectTaskService.search(taskSearchRequest.getTask(), 10, 0, - "default", null, false); + "default", null, false).getResponse(); assertEquals(1, projectTasks.size()); } diff --git a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectBeneficiaryApiControllerTest.java b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectBeneficiaryApiControllerTest.java index d7705cbd0e8..264d9336590 100644 --- a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectBeneficiaryApiControllerTest.java +++ b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectBeneficiaryApiControllerTest.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.BeneficiaryBulkResponse; import org.egov.common.models.project.BeneficiaryRequest; import org.egov.common.models.project.BeneficiaryResponse; @@ -16,8 +17,8 @@ import org.egov.project.service.ProjectService; import org.egov.project.service.ProjectStaffService; import org.egov.project.service.ProjectTaskService; -import org.egov.project.web.models.BeneficiarySearchRequest; -import org.egov.project.web.models.ProjectBeneficiarySearch; +import org.egov.common.models.project.BeneficiarySearchRequest; +import org.egov.common.models.project.ProjectBeneficiarySearch; import org.egov.tracer.model.CustomException; import org.egov.tracer.model.ErrorRes; import org.junit.jupiter.api.DisplayName; @@ -216,7 +217,7 @@ void shouldSend400BadRequestInCaseOfIncorrectApiOperationForUpdate() throws Exce void shouldAcceptSearchRequestAndReturnProjectStaff() throws Exception { BeneficiarySearchRequest beneficiarySearchRequest = BeneficiarySearchRequest.builder().projectBeneficiary( - ProjectBeneficiarySearch.builder().projectId("12").build() + ProjectBeneficiarySearch.builder().projectId(Arrays.asList("12","11")).build() ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); when(projectBeneficiaryService.search(any(BeneficiarySearchRequest.class), @@ -224,7 +225,7 @@ void shouldAcceptSearchRequestAndReturnProjectStaff() throws Exception { any(Integer.class), any(String.class), any(Long.class), - any(Boolean.class))).thenReturn(Arrays.asList(ProjectBeneficiaryTestBuilder.builder().withId().withAuditDetails().build())); + any(Boolean.class))).thenReturn(SearchResponse.builder().response(Arrays.asList(ProjectBeneficiaryTestBuilder.builder().withId().withAuditDetails().build())).build()); final MvcResult result = mockMvc.perform(post( "/beneficiary/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") @@ -245,7 +246,7 @@ void shouldAcceptSearchRequestAndReturnProjectStaff() throws Exception { void shouldThrowExceptionIfNoResultFound() throws Exception { BeneficiarySearchRequest beneficiarySearchRequest = BeneficiarySearchRequest.builder().projectBeneficiary( - ProjectBeneficiarySearch.builder().projectId("12").build() + ProjectBeneficiarySearch.builder().projectId(Arrays.asList("12","11")).build() ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); when(projectBeneficiaryService.search(any(BeneficiarySearchRequest.class), diff --git a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectFacilityApiControllerTest.java b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectFacilityApiControllerTest.java index 156b3a53a2a..e6a97cf70c8 100644 --- a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectFacilityApiControllerTest.java +++ b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectFacilityApiControllerTest.java @@ -18,8 +18,8 @@ import org.egov.project.service.ProjectService; import org.egov.project.service.ProjectStaffService; import org.egov.project.service.ProjectTaskService; -import org.egov.project.web.models.ProjectFacilitySearch; -import org.egov.project.web.models.ProjectFacilitySearchRequest; +import org.egov.common.models.project.ProjectFacilitySearch; +import org.egov.common.models.project.ProjectFacilitySearchRequest; import org.egov.tracer.model.ErrorRes; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; diff --git a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectStaffApiControllerTest.java b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectStaffApiControllerTest.java index eb7e38fed50..1e1b5409485 100644 --- a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectStaffApiControllerTest.java +++ b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectStaffApiControllerTest.java @@ -16,8 +16,8 @@ import org.egov.project.service.ProjectService; import org.egov.project.service.ProjectStaffService; import org.egov.project.service.ProjectTaskService; -import org.egov.project.web.models.ProjectStaffSearch; -import org.egov.project.web.models.ProjectStaffSearchRequest; +import org.egov.common.models.project.ProjectStaffSearch; +import org.egov.common.models.project.ProjectStaffSearchRequest; import org.egov.tracer.model.ErrorRes; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -168,7 +168,7 @@ void shouldSendErrorResWithErrorDetailsWith400BadRequestForUpdate() throws Excep void shouldAcceptSearchRequestAndReturnProjectStaff() throws Exception { ProjectStaffSearchRequest projectStaffSearchRequest = ProjectStaffSearchRequest.builder().projectStaff( - ProjectStaffSearch.builder().projectId("12").build() + ProjectStaffSearch.builder().projectId(Arrays.asList("12","11")).build() ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); when(projectStaffService.search(any(ProjectStaffSearchRequest.class), any(Integer.class), diff --git a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectTaskApiControllerTest.java b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectTaskApiControllerTest.java index 9da98813641..4288828d158 100644 --- a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectTaskApiControllerTest.java +++ b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectTaskApiControllerTest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskRequest; import org.egov.common.models.project.TaskSearch; import org.egov.common.models.project.TaskSearchRequest; @@ -23,8 +25,6 @@ import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import java.util.Collections; - import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -81,7 +81,7 @@ void shouldPassSearchRequestIfQueryParamsArePresent() throws Exception { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .task(TaskSearch.builder().build()).build(); when(projectTaskService.search(any(TaskSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), any(), any())).thenReturn(SearchResponse.builder().build()); mockMvc.perform(post("/task/v1/_search?limit=10&offset=0&tenantId=default").contentType(MediaType .APPLICATION_JSON).content(objectMapper.writeValueAsString(taskSearchRequest))) @@ -95,7 +95,7 @@ void shouldFailSearchRequestIfQueryParamsAreMissing() throws Exception { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .task(TaskSearch.builder().build()).build(); when(projectTaskService.search(any(TaskSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(SearchResponse.builder().build()); mockMvc.perform(post("/task/v1/_search?limit=10&offset=0").contentType(MediaType .APPLICATION_JSON).content(objectMapper.writeValueAsString(taskSearchRequest))) diff --git a/health-services/referralmanagement/CHANGELOG.md b/health-services/referralmanagement/CHANGELOG.md new file mode 100644 index 00000000000..a1f5546b24e --- /dev/null +++ b/health-services/referralmanagement/CHANGELOG.md @@ -0,0 +1,27 @@ +# Changelog +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 +- Upgraded to Core 2.9LTS +- Client reference ID validation added +- Upgraded to health models 1.0.20 and health common 1.0.16 +- Boundary v2 Integration +- MDMS v2 integration +- 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 + +## 1.0.1 - 2024-02-28 +- Added functionality for referrals handled by health facilities, referred to as "hfreferral". + +## 1.0.0 - 2023-11-15 + - Added Downsync Feature + +## 1.0.0-beta + - Base version + - Added functionality for Side-Effects and Refferal management diff --git a/health-services/referralmanagement/LOCALSETUP.md b/health-services/referralmanagement/LOCALSETUP.md new file mode 100644 index 00000000000..4f43fccdc4f --- /dev/null +++ b/health-services/referralmanagement/LOCALSETUP.md @@ -0,0 +1,31 @@ +# Local Setup + +To setup the Project service in your local system, clone the [Health campaign services](https://github.com/egovernments/health-campaign-services). + +## Dependencies + +### Infra Dependency + +- [X] Postgres DB +- [X] Redis +- [X] Elasticsearch +- [X] Kafka + - [X] Consumer + - [X] Producer + + +## Running Locally + +You can use docker-compose file to get started with these dependencies. Download docker-compose.yml from [here](../libraries/docker-compose.yml) + +Use the following command to start containers + +``` +cd path/to/docker-compose.yml file + +docker-compose up -d +``` + +To run it locally this service require port forwarding for idgen service, facility service and project service. + +Directly run the application. \ No newline at end of file diff --git a/health-services/referralmanagement/pom.xml b/health-services/referralmanagement/pom.xml new file mode 100644 index 00000000000..b9d85ad8269 --- /dev/null +++ b/health-services/referralmanagement/pom.xml @@ -0,0 +1,135 @@ + + + + 4.0.0 + org.egov + referralmanagement + jar + referralmanagement + 1.0.3 + + 17 + ${java.version} + ${java.version} + 1.18.22 + + + org.springframework.boot + spring-boot-starter-parent + 3.2.2 + + + src/main/java + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.egov.common + health-services-common + 1.0.18-SNAPSHOT + + + org.egov.common + health-services-models + 1.0.20-SNAPSHOT + compile + + + org.springframework.boot + spring-boot-starter-data-redis + + + io.lettuce + lettuce-core + + + + + redis.clients + jedis + + + + org.springframework.boot + spring-boot-devtools + + + org.flywaydb + flyway-core + 9.22.3 + + + org.postgresql + postgresql + 42.7.1 + + + org.egov.services + tracer + 2.9.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-test + test + + + io.swagger + swagger-core + 1.5.18 + + + org.projectlombok + lombok + ${lombok.version} + true + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + + + repo.egovernments.org + eGov ERP Releases Repository + https://nexus-repo.egovernments.org/nexus/content/repositories/releases/ + + + repo.egovernments.org.snapshots + eGov ERP Releases Repository + https://nexus-repo.egovernments.org/nexus/content/repositories/snapshots/ + + + repo.egovernments.org.public + eGov Public Repository Group + https://nexus-repo.egovernments.org/nexus/content/groups/public/ + + + repo.digit.org + eGov DIGIT Releases Repository + https://nexus-repo.digit.org/nexus/content/repositories/snapshots/ + + + \ No newline at end of file diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java new file mode 100644 index 00000000000..b24119eb8dd --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java @@ -0,0 +1,25 @@ +package org.egov.referralmanagement; + +public interface Constants { + + String SET_SIDE_EFFECTS = "setSideEffects"; + String GET_SIDE_EFFECTS = "getSideEffects"; + String SET_REFERRALS = "setReferrals"; + String GET_REFERRALS = "getReferrals"; + String SET_HF_REFERRALS = "setHfReferrals"; + String GET_HF_REFERRALS = "getHfReferrals"; + String VALIDATION_ERROR = "VALIDATION_ERROR"; + String PROJECT_TYPES = "projectTypes"; + String MDMS_RESPONSE = "MdmsRes"; + String INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR"; + String GET_ID = "getId"; + String STAFF = "STAFF"; + String FACILITY = "FACILITY"; + + public static final String HCM_MASTER_PROJECTTYPE = "projectTypes"; + public static final String HCM_MDMS_PROJECT_MODULE_NAME = "HCM-PROJECT-TYPES"; + public static final String HCM_PROJECT_TYPE_FILTER_CODE = "$.[?(@.code=='%s')]"; + public static final String HCM_MDMS_PROJECTTYPE_RES_PATH = "$.MdmsRes." + HCM_MDMS_PROJECT_MODULE_NAME + "." + HCM_MASTER_PROJECTTYPE + ".*"; + + String INVALID_RECIPIENT_TYPE = "Invalid Recipient Type"; +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/ReferralManagementApplication.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/ReferralManagementApplication.java new file mode 100644 index 00000000000..03494a4c86b --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/ReferralManagementApplication.java @@ -0,0 +1,18 @@ +package org.egov.referralmanagement; + + +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Import; + +@SpringBootApplication +@EnableCaching +@Import({ TracerConfiguration.class }) +public class ReferralManagementApplication +{ + public static void main(String[] args) throws Exception { + SpringApplication.run(ReferralManagementApplication.class, args); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/MainConfiguration.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/MainConfiguration.java new file mode 100644 index 00000000000..dfd9401a2d7 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/MainConfiguration.java @@ -0,0 +1,92 @@ +package org.egov.referralmanagement.config; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.RedisStandaloneConfiguration; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; + +import jakarta.annotation.PostConstruct; +import java.util.TimeZone; + +@Import({TracerConfiguration.class}) +@Configuration +@ComponentScan(basePackages = {"org.egov"}) +public class MainConfiguration { + + @Value("${app.timezone}") + private String timeZone; + + @Value("${spring.redis.host}") + private String redisHost; + + @PostConstruct + public void initialize() { + TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); + } + + @Bean + @Qualifier("objectMapper") + public ObjectMapper objectMapper(){ + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).setTimeZone(TimeZone.getTimeZone(timeZone)); + objectMapper.registerModule(new JavaTimeModule()); + return objectMapper; + } + + @Bean + @Qualifier("redisObjectMapper") + public ObjectMapper redisObjectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, + ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY); + objectMapper.registerModule(new JavaTimeModule()); + return objectMapper; + } + + @Bean + public MappingJackson2HttpMessageConverter jacksonConverter(ObjectMapper objectMapper) { + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + converter.setObjectMapper(objectMapper); + return converter; + } + + @Bean + public RedisConnectionFactory redisConnectionFactory() { + RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(); + redisStandaloneConfiguration.setHostName(redisHost); + return new JedisConnectionFactory(redisStandaloneConfiguration); + } + + + @Bean + public RedisTemplate redisTemplate(@Qualifier("redisObjectMapper") ObjectMapper redisObjectMapper, + RedisConnectionFactory redisConnectionFactory) { + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(redisObjectMapper, Object.class); + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(serializer); + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashValueSerializer(serializer); + redisTemplate.afterPropertiesSet(); + return redisTemplate; + } +} \ No newline at end of file diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java new file mode 100644 index 00000000000..e69325f19c5 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java @@ -0,0 +1,118 @@ +package org.egov.referralmanagement.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Component +public class ReferralManagementConfiguration { + @Value("${referralmanagement.sideeffect.kafka.create.topic}") + private String createSideEffectTopic; + + @Value("${referralmanagement.sideeffect.kafka.update.topic}") + private String updateSideEffectTopic; + + @Value("${referralmanagement.sideeffect.kafka.delete.topic}") + private String deleteSideEffectTopic; + + @Value("${referralmanagement.sideeffect.consumer.bulk.create.topic}") + private String createSideEffectBulkTopic; + + @Value("${referralmanagement.sideeffect.consumer.bulk.update.topic}") + private String updateSideEffectBulkTopic; + + @Value("${referralmanagement.sideeffect.consumer.bulk.delete.topic}") + private String deleteSideEffectBulkTopic; + + @Value("${egov.project.host}") + private String projectHost; + + @Value("${egov.search.project.task.url}") + private String projectTaskSearchUrl; + + @Value("${egov.search.project.beneficiary.url}") + private String projectBeneficiarySearchUrl; + + @Value("${referralmanagement.referral.kafka.create.topic}") + private String createReferralTopic; + + @Value("${referralmanagement.referral.kafka.update.topic}") + private String updateReferralTopic; + + @Value("${referralmanagement.referral.kafka.delete.topic}") + private String deleteReferralTopic; + + @Value("${referralmanagement.referral.consumer.bulk.create.topic}") + private String createReferralBulkTopic; + + @Value("${referralmanagement.referral.consumer.bulk.update.topic}") + private String updateReferralBulkTopic; + + @Value("${referralmanagement.referral.consumer.bulk.delete.topic}") + private String deleteReferralBulkTopic; + + @Value("${referralmanagement.hfreferral.kafka.create.topic}") + private String createHFReferralTopic; + + @Value("${referralmanagement.hfreferral.kafka.update.topic}") + private String updateHFReferralTopic; + + @Value("${referralmanagement.hfreferral.kafka.delete.topic}") + private String deleteHFReferralTopic; + + @Value("${referralmanagement.hfreferral.consumer.bulk.create.topic}") + private String createHFReferralBulkTopic; + + @Value("${referralmanagement.hfreferral.consumer.bulk.update.topic}") + private String updateHFReferralBulkTopic; + + @Value("${referralmanagement.hfreferral.consumer.bulk.delete.topic}") + private String deleteHFReferralBulkTopic; + + @Value("${egov.search.project.staff.url}") + private String projectStaffSearchUrl; + + @Value("${egov.search.project.facility.url}") + private String projectFacilitySearchUrl; + + @Value("${egov.search.project.url}") + private String projectSearchUrl; + + @Value("${egov.facility.host}") + private String facilityHost; + + @Value("${egov.search.facility.url}") + private String facilitySearchUrl; + + @Value("${egov.household.host}") + private String householdHost; + + @Value("${egov.search.household.url}") + private String householdSearchUrl; + + @Value("${egov.search.household.member.url}") + private String householdMemberSearchUrl; + + @Value("${egov.individual.host}") + private String individualHost; + + @Value("${egov.search.individual.url}") + private String individualSearchUrl; + + @Value("${egov.mdms.host}") + private String mdmsHost; + + @Value("${egov.mdms.search.endpoint}") + private String mdmsSearchUrl; + +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/HFReferralConsumer.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/HFReferralConsumer.java new file mode 100644 index 00000000000..d4b4469df52 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/HFReferralConsumer.java @@ -0,0 +1,110 @@ +package org.egov.referralmanagement.consumer; + +import java.util.Map; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.referralmanagement.service.HFReferralService; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Component; + +/** + * Kafka Consumer for handling HFReferral-related messages. + * Author: kanishq-egov + */ +@Component +@Slf4j +public class HFReferralConsumer { + + private final HFReferralService hfReferralService; + private final ObjectMapper objectMapper; + + @Autowired + public HFReferralConsumer(HFReferralService hfReferralService, + @Qualifier("objectMapper") ObjectMapper objectMapper) { + this.hfReferralService = hfReferralService; + this.objectMapper = objectMapper; + } + + /** + * Kafka listener method to handle bulk creation of HFReferrals. + * Author: kanishq-egov + * + * @param consumerRecord The Kafka message payload. + * @param topic The Kafka topic from which the message is received. + */ + @KafkaListener(topics = "${referralmanagement.hfreferral.consumer.bulk.create.topic}") + public void bulkCreate(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + // Convert the Kafka message payload to HFReferralBulkRequest + HFReferralBulkRequest request = objectMapper.convertValue(consumerRecord, HFReferralBulkRequest.class); + + // Invoke the HFReferralService to handle bulk creation + hfReferralService.create(request, true); + } catch (Exception exception) { + log.error("Error in HFReferral consumer bulk create", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + + // Throw a CustomException in case of an error during bulk creation + throw new CustomException("HCM_REFERRAL_MANAGEMENT_REFERRAL_CREATE", exception.getMessage()); + } + } + + /** + * Kafka listener method to handle bulk update of HFReferrals. + * Author: kanishq-egov + * + * @param consumerRecord The Kafka message payload. + * @param topic The Kafka topic from which the message is received. + */ + @KafkaListener(topics = "${referralmanagement.hfreferral.consumer.bulk.update.topic}") + public void bulkUpdate(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + // Convert the Kafka message payload to HFReferralBulkRequest + HFReferralBulkRequest request = objectMapper.convertValue(consumerRecord, HFReferralBulkRequest.class); + + // Invoke the HFReferralService to handle bulk update + hfReferralService.update(request, true); + } catch (Exception exception) { + log.error("Error in HFReferral consumer bulk update", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + + // Throw a CustomException in case of an error during bulk update + throw new CustomException("HCM_REFERRAL_MANAGEMENT_REFERRAL_UPDATE", exception.getMessage()); + } + } + + /** + * Kafka listener method to handle bulk deletion of HFReferrals. + * Author: kanishq-egov + * + * @param consumerRecord The Kafka message payload. + * @param topic The Kafka topic from which the message is received. + */ + @KafkaListener(topics = "${referralmanagement.hfreferral.consumer.bulk.delete.topic}") + public void bulkDelete(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + // Convert the Kafka message payload to HFReferralBulkRequest + HFReferralBulkRequest request = objectMapper.convertValue(consumerRecord, HFReferralBulkRequest.class); + + // Invoke the HFReferralService to handle bulk deletion + hfReferralService.delete(request, true); + } catch (Exception exception) { + log.error("Error in HFReferral consumer bulk delete", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + + // Throw a CustomException in case of an error during bulk deletion + throw new CustomException("HCM_REFERRAL_MANAGEMENT_REFERRAL_DELETE", exception.getMessage()); + } + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java new file mode 100644 index 00000000000..4e810216f06 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java @@ -0,0 +1,71 @@ +package org.egov.referralmanagement.consumer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.referralmanagement.service.ReferralManagementService; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +@Slf4j +public class ReferralManagementConsumer { + + private final ReferralManagementService referralManagementService; + + private final ObjectMapper objectMapper; + + @Autowired + public ReferralManagementConsumer(ReferralManagementService referralManagementService, + @Qualifier("objectMapper") ObjectMapper objectMapper) { + this.referralManagementService = referralManagementService; + this.objectMapper = objectMapper; + } + + @KafkaListener(topics = "${referralmanagement.referral.consumer.bulk.create.topic}") + public void bulkCreate(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + ReferralBulkRequest request = objectMapper.convertValue(consumerRecord, ReferralBulkRequest.class); + referralManagementService.create(request, true); + } catch (Exception exception) { + log.error("Error in Referral consumer bulk create", exception); + log.error("Exception trace: {}", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_REFERRAL_MANAGEMENT_REFERRAL_CREATE", exception.getMessage()); + } + } + + @KafkaListener(topics = "${referralmanagement.referral.consumer.bulk.update.topic}") + public void bulkUpdate(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + ReferralBulkRequest request = objectMapper.convertValue(consumerRecord, ReferralBulkRequest.class); + referralManagementService.update(request, true); + } catch (Exception exception) { + log.error("Error in Referral consumer bulk update", exception); + log.error("Exception trace: {}", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_REFERRAL_MANAGEMENT_REFERRAL_UPDATE", exception.getMessage()); + } + } + + @KafkaListener(topics = "${referralmanagement.referral.consumer.bulk.delete.topic}") + public void bulkDelete(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + ReferralBulkRequest request = objectMapper.convertValue(consumerRecord, ReferralBulkRequest.class); + referralManagementService.delete(request, true); + } catch (Exception exception) { + log.error("Error in Referral consumer bulk delete", exception); + log.error("Exception trace: {}", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_REFERRAL_MANAGEMENT_REFERRAL_DELETE", exception.getMessage()); + } + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java new file mode 100644 index 00000000000..10cfbddb1db --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java @@ -0,0 +1,71 @@ +package org.egov.referralmanagement.consumer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.referralmanagement.service.SideEffectService; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +@Slf4j +public class SideEffectConsumer { + + private final SideEffectService sideEffectService; + + private final ObjectMapper objectMapper; + + @Autowired + public SideEffectConsumer(SideEffectService sideEffectService, + @Qualifier("objectMapper") ObjectMapper objectMapper) { + this.sideEffectService = sideEffectService; + this.objectMapper = objectMapper; + } + + @KafkaListener(topics = "${referralmanagement.sideeffect.consumer.bulk.create.topic}") + public void bulkCreate(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + SideEffectBulkRequest request = objectMapper.convertValue(consumerRecord, SideEffectBulkRequest.class); + sideEffectService.create(request, true); + } catch (Exception exception) { + log.error("Error in Side Effect consumer bulk create", exception); + log.error("Exception trace: {}", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_REFERRAL_MANAGEMENT_SIDE_EFFECT_CREATE", exception.getMessage()); + } + } + + @KafkaListener(topics = "${referralmanagement.sideeffect.consumer.bulk.update.topic}") + public void bulkUpdate(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + SideEffectBulkRequest request = objectMapper.convertValue(consumerRecord, SideEffectBulkRequest.class); + sideEffectService.update(request, true); + } catch (Exception exception) { + log.error("Error in Side Effect consumer bulk update", exception); + log.error("Exception trace: {}", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_REFERRAL_MANAGEMENT_SIDE_EFFECT_UPDATE", exception.getMessage()); + } + } + + @KafkaListener(topics = "${referralmanagement.sideeffect.consumer.bulk.delete.topic}") + public void bulkDelete(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + SideEffectBulkRequest request = objectMapper.convertValue(consumerRecord, SideEffectBulkRequest.class); + sideEffectService.delete(request, true); + } catch (Exception exception) { + log.error("Error in Side Effect consumer bulk delete", exception); + log.error("Exception trace: {}", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_REFERRAL_MANAGEMENT_SIDE_EFFECT_DELETE", exception.getMessage()); + } + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java new file mode 100644 index 00000000000..d2d43634030 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java @@ -0,0 +1,159 @@ +package org.egov.referralmanagement.repository; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.builder.GenericQueryBuilder; +import org.egov.common.data.query.builder.QueryFieldChecker; +import org.egov.common.data.query.builder.SelectQueryBuilder; +import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralSearch; +import org.egov.common.producer.Producer; +import org.egov.referralmanagement.repository.rowmapper.HFReferralRowMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdMethod; + +/** + * Repository class for managing the persistence and retrieval of HFReferral entities. + * This class extends GenericRepository for common CRUD operations. + * + * @author kanishq-egov + */ +@Repository +@Slf4j +public class HFReferralRepository extends GenericRepository { + + @Autowired + private HFReferralRowMapper rowMapper; + + /** + * Constructor for HFReferralRepository. + * + * @param producer The producer for publishing messages. + * @param namedParameterJdbcTemplate JDBC template for named parameters. + * @param redisTemplate Template for Redis operations. + * @param selectQueryBuilder Builder for creating SELECT queries. + * @param rowMapper Mapper for converting rows to HFReferral objects. + */ + @Autowired + protected HFReferralRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, + RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, + HFReferralRowMapper rowMapper) { + // Call the constructor of the GenericRepository with necessary parameters. + super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, rowMapper, Optional.of("hf_referral")); + } + + /** + * Retrieves a list of HFReferrals based on the provided search criteria. + * + * @param searchObject The search criteria for filtering HFReferrals. + * @param limit The maximum number of records to retrieve. + * @param offset The offset for pagination. + * @param tenantId The tenant ID for filtering. + * @param lastChangedSince Timestamp for filtering records changed since this time. + * @param includeDeleted Flag indicating whether to include deleted records. + * @return A list of HFReferral entities matching the search criteria. + */ + public List find(HFReferralSearch searchObject, Integer limit, Integer offset, String tenantId, + Long lastChangedSince, Boolean includeDeleted) { + // Initial query to select HFReferral fields from the table. + String query = "SELECT hf.id, hf.clientreferenceid, hf.tenantid, hf.projectid, hf.projectfacilityid, hf.symptom, hf.symptomsurveyid, hf.beneficiaryid, hf.referralcode, hf.nationallevelid, hf.createdby, hf.createdtime, hf.lastmodifiedby, hf.lastmodifiedtime, hf.clientcreatedby, hf.clientcreatedtime, hf.clientlastmodifiedby, hf.clientlastmodifiedtime, hf.rowversion, hf.isdeleted, hf.additionaldetails from hf_referral hf"; + Map paramsMap = new HashMap<>(); + + // Generate WHERE conditions based on non-null fields in the search object. + List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, + QueryFieldChecker.isNotNull, paramsMap); + + // Apply the WHERE conditions to the query. + query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); + query = query.replace("id IN (:id)", "hf.id IN (:id)"); + query = query.replace("clientReferenceId IN (:clientReferenceId)", "hf.clientReferenceId IN (:clientReferenceId)"); + + // Add additional conditions based on tenant ID, includeDeleted, and lastChangedSince. + if(CollectionUtils.isEmpty(whereFields)) { + query = query + " where hf.tenantId=:tenantId "; + } else { + query = query + " and hf.tenantId=:tenantId "; + } + if (Boolean.FALSE.equals(includeDeleted)) { + query = query + "and hf.isDeleted=:isDeleted "; + } + + if (lastChangedSince != null) { + query = query + "and hf.lastModifiedTime>=:lastModifiedTime "; + } + + // Add ORDER BY, LIMIT, and OFFSET clauses to the query. + query = query + "ORDER BY hf.createdtime DESC LIMIT :limit OFFSET :offset"; + paramsMap.put("tenantId", tenantId); + paramsMap.put("isDeleted", includeDeleted); + paramsMap.put("lastModifiedTime", lastChangedSince); + paramsMap.put("limit", limit); + paramsMap.put("offset", offset); + + // Execute the query and retrieve the list of HFReferral entities. + List hfReferralList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + return hfReferralList; + } + + /** + * Retrieves a list of HFReferrals based on a list of IDs. + * + * @param ids The list of IDs to search for. + * @param includeDeleted Flag indicating whether to include deleted records. + * @param columnName The column name to search for IDs. + * @return A list of HFReferral entities matching the provided IDs. + */ + public List findById(List ids, Boolean includeDeleted, String columnName) { + // Find objects in the cache based on the provided IDs. + List objFound = findInCache(ids); + if (!includeDeleted) { + objFound = objFound.stream() + .filter(entity -> entity.getIsDeleted().equals(false)) + .collect(Collectors.toList()); + } + + // If objects are found in the cache, check if there are any IDs remaining to be retrieved. + if (!objFound.isEmpty()) { + Method idMethod = getIdMethod(objFound, columnName); + ids.removeAll(objFound.stream() + .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) + .collect(Collectors.toList())); + + // If no IDs are remaining, return the objects found in the cache. + if (ids.isEmpty()) { + return objFound; + } + } + + // Generate a SELECT query based on the provided IDs and column name. + String query = String.format("SELECT hf.id, hf.clientreferenceid, hf.tenantid, hf.projectid, hf.projectfacilityid, hf.symptom, hf.symptomsurveyid, hf.beneficiaryid, hf.referralcode, hf.nationallevelid, hf.createdby, hf.createdtime, hf.lastmodifiedby, hf.lastmodifiedtime, hf.clientcreatedby, hf.clientcreatedtime, hf.clientlastmodifiedby, hf.clientlastmodifiedtime, hf.rowversion, hf.isdeleted, hf.additionaldetails from hf_referral hf WHERE hf.%s IN (:ids) ", columnName); + + // Add conditions to exclude deleted records if includeDeleted is false. + if (includeDeleted == null || !includeDeleted) { + query += " AND hf.isDeleted = false "; + } + + // Create parameter map for the query and execute it to retrieve HFReferral entities. + Map paramMap = new HashMap<>(); + paramMap.put("ids", ids); + List hfReferralList = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + + // Add the retrieved entities to the cache. + objFound.addAll(hfReferralList); + putInCache(objFound); + return objFound; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java new file mode 100644 index 00000000000..aa002b560e1 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java @@ -0,0 +1,110 @@ +package org.egov.referralmanagement.repository; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.builder.GenericQueryBuilder; +import org.egov.common.data.query.builder.QueryFieldChecker; +import org.egov.common.data.query.builder.SelectQueryBuilder; +import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralSearch; +import org.egov.common.producer.Producer; +import org.egov.referralmanagement.repository.rowmapper.ReferralRowMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; +import static org.egov.common.utils.CommonUtils.getIdMethod; + +@Repository +@Slf4j +public class ReferralRepository extends GenericRepository { + @Autowired + private ReferralRowMapper rowMapper; + + @Autowired + protected ReferralRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, + RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, + ReferralRowMapper rowMapper) { + super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, rowMapper, Optional.of("referral")); + } + + public SearchResponse find(ReferralSearch searchObject, Integer limit, Integer offset, String tenantId, + Long lastChangedSince, Boolean includeDeleted) { + + String query = "SELECT r.id, r.clientreferenceid, r.tenantid, r.projectbeneficiaryid, r.projectbeneficiaryclientreferenceid, r.referrerid, r.recipientid, r.recipienttype, r.reasons, r.sideeffectid, r.referralCode, r.sideeffectclientreferenceid, r.createdby, r.createdtime, r.lastmodifiedby, r.lastmodifiedtime, r.clientcreatedby, r.clientcreatedtime, r.clientlastmodifiedby, r.clientlastmodifiedtime, r.rowversion, r.isdeleted, r.additionaldetails, se.id sId, se.clientreferenceid sClientReferenceId, se.tenantid sTenantId, se.taskid sTaskId, se.taskclientreferenceid sTaskClientReferenceId, se.projectbeneficiaryId sProjectBeneficiaryId, se.projectBeneficiaryClientReferenceId sProjectBeneficiaryClientReferenceId, se.symptoms sSymptoms, se.additionalDetails sAdditionalDetails, se.createdby sCreatedBy, se.createdtime sCreatedTime, se.lastmodifiedby sLastModifiedBy, se.lastmodifiedtime sLastModifiedTime, se.clientCreatedBy sClientCreatedBy, se.clientcreatedtime sClientCreatedTime, se.clientlastmodifiedby sClientLastModifiedBy, se.clientlastmodifiedtime sClientLastModifiedTime, se.rowversion sRowVersion, se.isdeleted sIsDeleted FROM referral r left join side_effect se on r.sideEffectClientReferenceid = se.clientreferenceid"; + Map paramsMap = new HashMap<>(); + List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, + QueryFieldChecker.isNotNull, paramsMap); + query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); + query = query.replace("id IN (:id)", "r.id IN (:id)"); + query = query.replace("clientReferenceId IN (:clientReferenceId)", "r.clientReferenceId IN (:clientReferenceId)"); + query = query.replace("projectBeneficiaryClientReferenceId IN (:projectBeneficiaryClientReferenceId)", "r.projectBeneficiaryClientReferenceId IN (:projectBeneficiaryClientReferenceId)"); + query = query.replace("projectBeneficiaryId IN (:projectBeneficiaryId)", "r.projectBeneficiaryId IN (:projectBeneficiaryId)"); + + if(CollectionUtils.isEmpty(whereFields)) { + query = query + " where r.tenantId=:tenantId "; + } else { + query = query + " and r.tenantId=:tenantId "; + } + if (Boolean.FALSE.equals(includeDeleted)) { + query = query + "and r.isDeleted=:isDeleted "; + } + + if (lastChangedSince != null) { + query = query + "and r.lastModifiedTime>=:lastModifiedTime "; + } + paramsMap.put("tenantId", tenantId); + paramsMap.put("isDeleted", includeDeleted); + paramsMap.put("lastModifiedTime", lastChangedSince); + + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + + query = query + "ORDER BY r.createdtime ASC LIMIT :limit OFFSET :offset"; + paramsMap.put("limit", limit); + paramsMap.put("offset", offset); + List referralList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + return SearchResponse.builder().response(referralList).totalCount(totalCount).build(); + } + + public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { + List objFound = findInCache(ids); + if (!includeDeleted) { + objFound = objFound.stream() + .filter(entity -> entity.getIsDeleted().equals(false)) + .collect(Collectors.toList()); + } + if (!objFound.isEmpty()) { + Method idMethod = getIdMethod(objFound, columnName); + ids.removeAll(objFound.stream() + .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) + .collect(Collectors.toList())); + if (ids.isEmpty()) { + return SearchResponse.builder().response(objFound).build(); + } + } + + String query = String.format("SELECT r.id, r.clientreferenceid, r.tenantid, r.projectbeneficiaryid, r.projectbeneficiaryclientreferenceid, r.referrerid, r.recipientid, r.recipienttype, r.reasons, r.sideeffectid, r.referralCode, r.sideeffectclientreferenceid, r.createdby, r.createdtime, r.lastmodifiedby, r.lastmodifiedtime, r.clientcreatedby, r.clientcreatedtime, r.clientlastmodifiedby, r.clientlastmodifiedtime, r.rowversion, r.isdeleted, r.additionaldetails, se.id sId, se.clientreferenceid sClientReferenceId, se.tenantid sTenantId, se.taskid sTaskId, se.taskclientreferenceid sTaskClientReferenceId, se.projectbeneficiaryId sProjectBeneficiaryId, se.projectBeneficiaryClientReferenceId sProjectBeneficiaryClientReferenceId, se.symptoms sSymptoms, se.additionalDetails sAdditionalDetails, se.createdby sCreatedBy, se.createdtime sCreatedTime, se.lastmodifiedby sLastModifiedBy, se.lastmodifiedtime sLastModifiedTime, se.clientCreatedBy sClientCreatedBy, se.clientcreatedtime sClientCreatedTime, se.clientlastmodifiedby sClientLastModifiedBy, se.clientlastmodifiedtime sClientLastModifiedTime, se.rowversion sRowVersion, se.isdeleted sIsDeleted FROM referral r left join side_effect se on r.sideEffectClientReferenceid = se.clientreferenceid WHERE r.%s IN (:ids) ", columnName); + if (includeDeleted == null || !includeDeleted) { + query += " AND r.isDeleted = false "; + } + Map paramMap = new HashMap<>(); + paramMap.put("ids", ids); + List referralList = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + + objFound.addAll(referralList); + putInCache(objFound); + return SearchResponse.builder().response(objFound).build(); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java new file mode 100644 index 00000000000..06301c2c211 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java @@ -0,0 +1,139 @@ +package org.egov.referralmanagement.repository; + +import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; +import static org.egov.common.utils.CommonUtils.getIdList; +import static org.egov.common.utils.CommonUtils.getIdMethod; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.egov.common.data.query.builder.GenericQueryBuilder; +import org.egov.common.data.query.builder.QueryFieldChecker; +import org.egov.common.data.query.builder.SelectQueryBuilder; +import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.project.Task; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; +import org.egov.common.producer.Producer; +import org.egov.referralmanagement.repository.rowmapper.SideEffectRowMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ReflectionUtils; + +import lombok.extern.slf4j.Slf4j; + +@Repository +@Slf4j +public class SideEffectRepository extends GenericRepository { + @Autowired + private SideEffectRowMapper rowMapper; + + @Autowired + protected SideEffectRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, + RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, + SideEffectRowMapper rowMapper) { + super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, rowMapper, Optional.of("side_effect")); + } + + public Map> fetchSideEffects(List taskList) { + if (taskList.isEmpty()) { + return Collections.emptyMap(); + } + List taskIds = getIdList(taskList); + Map resourceParamsMap = new HashMap<>(); + String resourceQuery = "SELECT * FROM side_effect ae where ae.taskId IN (:taskIds)"; + resourceParamsMap.put("taskIds", taskIds); + List sideEffectList = this.namedParameterJdbcTemplate.query(resourceQuery, resourceParamsMap, + this.rowMapper); + Map> idToObjMap = new HashMap<>(); + + sideEffectList.forEach(sideEffect -> { + String taskId = sideEffect.getTaskId(); + if (idToObjMap.containsKey(taskId)) { + idToObjMap.get(taskId).add(sideEffect); + } else { + List sideEffects = new ArrayList<>(); + sideEffects.add(sideEffect); + idToObjMap.put(taskId, sideEffects); + } + }); + return idToObjMap; + } + + public SearchResponse find(SideEffectSearch searchObject, Integer limit, Integer offset, String tenantId, + Long lastChangedSince, Boolean includeDeleted) { + + String query = "SELECT * FROM side_effect ae LEFT JOIN project_task pt ON ae.taskId = pt.id "; + Map paramsMap = new HashMap<>(); + List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, + QueryFieldChecker.isNotNull, paramsMap); + query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); + query = query.replace("id IN (:id)", "ae.id IN (:id)"); + query = query.replace("clientReferenceId IN (:clientReferenceId)", "ae.clientReferenceId IN (:clientReferenceId)"); + + if(CollectionUtils.isEmpty(whereFields)) { + query = query + " where ae.tenantId=:tenantId "; + } else { + query = query + " and ae.tenantId=:tenantId "; + } + if (Boolean.FALSE.equals(includeDeleted)) { + query = query + "and ae.isDeleted=:isDeleted "; + } + + if (lastChangedSince != null) { + query = query + "and as.lastModifiedTime>=:lastModifiedTime "; + } + paramsMap.put("tenantId", tenantId); + paramsMap.put("isDeleted", includeDeleted); + paramsMap.put("lastModifiedTime", lastChangedSince); + + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + + query = query + "ORDER BY ae.createdtime ASC LIMIT :limit OFFSET :offset"; + paramsMap.put("limit", limit); + paramsMap.put("offset", offset); + + List sideEffectList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + return SearchResponse.builder().response(sideEffectList).totalCount(totalCount).build(); + } + + public List findById(List ids, String columnName, Boolean includeDeleted) { + List objFound = findInCache(ids); + if (!includeDeleted) { + objFound = objFound.stream() + .filter(entity -> entity.getIsDeleted().equals(false)) + .collect(Collectors.toList()); + } + if (!objFound.isEmpty()) { + Method idMethod = getIdMethod(objFound, columnName); + ids.removeAll(objFound.stream() + .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) + .collect(Collectors.toList())); + if (ids.isEmpty()) { + return objFound; + } + } + + String query = String.format("SELECT * FROM side_effect ae LEFT JOIN project_task pt ON ae.taskid = pt.id WHERE ae.%s IN (:ids) ", columnName); + if (includeDeleted == null || !includeDeleted) { + query += " AND ae.isDeleted = false "; + } + Map paramMap = new HashMap<>(); + paramMap.put("ids", ids); + List sideEffectList = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + + objFound.addAll(sideEffectList); + putInCache(objFound); + return objFound; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java new file mode 100644 index 00000000000..5456cd9179c --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java @@ -0,0 +1,78 @@ +package org.egov.referralmanagement.repository.rowmapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import org.egov.common.models.core.AdditionalFields; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +/** + * RowMapper implementation for mapping ResultSet rows to HFReferral objects. + * This class is responsible for converting database query results into Java objects. + * + * @author kanishq-egov + */ +@Component +public class HFReferralRowMapper implements RowMapper { + + @Autowired + ObjectMapper objectMapper; + + /** + * Maps a ResultSet row to an HFReferral object. + * + * @param resultSet The result set containing the queried data. + * @param i The current row number. + * @return An HFReferral object mapped from the ResultSet row. + * @throws SQLException If there's an issue accessing ResultSet data. + */ + @Override + public HFReferral mapRow(ResultSet resultSet, int i) throws SQLException { + try { + // Create AuditDetails object from the ResultSet data. + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + + // Create clientAuditDetails object from the ResultSet data. + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("clientCreatedBy")) + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build(); + + // Build and return HFReferral object using ResultSet data and ObjectMapper for additionalFields. + return HFReferral.builder() + .id(resultSet.getString("id")) + .clientReferenceId(resultSet.getString("clientreferenceid")) + .tenantId(resultSet.getString("tenantid")) + .projectId(resultSet.getString("projectid")) + .projectFacilityId(resultSet.getString("projectfacilityid")) + .symptom(resultSet.getString("symptom")) + .symptomSurveyId(resultSet.getString("symptomsurveyid")) + .beneficiaryId(resultSet.getString("beneficiaryid")) + .referralCode(resultSet.getString("referralcode")) + .nationalLevelId(resultSet.getString("nationallevelid")) + .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper + .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) + .rowVersion(resultSet.getInt("rowversion")) + .isDeleted(resultSet.getBoolean("isdeleted")) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) + .build(); + } catch (JsonProcessingException e) { + // Wrap JsonProcessingException as a RuntimeException for simplicity. + throw new RuntimeException(e); + } + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java new file mode 100644 index 00000000000..181aa1b6a55 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java @@ -0,0 +1,111 @@ +package org.egov.referralmanagement.repository.rowmapper; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import org.egov.common.models.core.AdditionalFields; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +@Component +public class ReferralRowMapper implements RowMapper { + + @Autowired + ObjectMapper objectMapper; + + /** + * Maps a row of the ResultSet to a Referral object. + * + * @param resultSet the ResultSet containing the data from the database + * @param i the current row number + * @return a Referral object mapped from the ResultSet + * @throws SQLException if an SQL exception occurs + */ + @Override + public Referral mapRow(ResultSet resultSet, int i) throws SQLException { + try { + // Initialize sideEffect to null + SideEffect sideEffect = null; + // Check if side effect client reference ID is not null + String sideEffectClientReferenceId = resultSet.getString("sideEffectClientReferenceId"); + if (sideEffectClientReferenceId != null) { + // Map side effect AuditDetails + AuditDetails sideEffectAuditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("sCreatedBy")) + .createdTime(resultSet.getLong("sCreatedTime")) + .lastModifiedBy(resultSet.getString("sLastModifiedBy")) + .lastModifiedTime(resultSet.getLong("sLastModifiedTime")) + .build(); + // Map side effect client AuditDetails + AuditDetails sideEffectClientAuditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("sClientCreatedBy")) + .createdTime(resultSet.getLong("sClientCreatedTime")) + .lastModifiedBy(resultSet.getString("sClientLastModifiedBy")) + .lastModifiedTime(resultSet.getLong("sClientLastModifiedTime")) + .build(); + // Build SideEffect object + sideEffect = SideEffect.builder() + .id(resultSet.getString("sId")) + .additionalFields(resultSet.getString("sAdditionalDetails") == null ? null : objectMapper + .readValue(resultSet.getString("sAdditionalDetails"), AdditionalFields.class)) + .rowVersion(resultSet.getInt("sRowVersion")) + .isDeleted(resultSet.getBoolean("sIsDeleted")) + .auditDetails(sideEffectAuditDetails) + .tenantId(resultSet.getString("sTenantId")) + .clientAuditDetails(sideEffectClientAuditDetails) + .clientReferenceId(resultSet.getString("sClientReferenceId")) + .taskId(resultSet.getString("sTaskId")) + .taskClientReferenceId(resultSet.getString("sTaskClientReferenceId")) + .projectBeneficiaryId(resultSet.getString("sProjectBeneficiaryId")) + .projectBeneficiaryClientReferenceId(resultSet.getString("sProjectBeneficiaryClientReferenceId")) + .symptoms(resultSet.getString("sSymptoms") == null ? null : objectMapper + .readValue(resultSet.getString("sSymptoms"), ArrayList.class)) + .build(); + } + // Map main Referral AuditDetails + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + // Map main Referral client AuditDetails + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("clientCreatedBy")) + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build(); + // Build Referral object + return Referral.builder() + .id(resultSet.getString("id")) + .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper + .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) + .rowVersion(resultSet.getInt("rowversion")) + .isDeleted(resultSet.getBoolean("isdeleted")) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) + .clientReferenceId(resultSet.getString("clientreferenceid")) + .projectBeneficiaryId(resultSet.getString("projectBeneficiaryId")) + .projectBeneficiaryClientReferenceId(resultSet.getString("projectbeneficiaryclientreferenceid")) + .referrerId(resultSet.getString("referrerId")) + .recipientId(resultSet.getString("recipientId")) + .recipientType(resultSet.getString("recipientType")) + .sideEffect(sideEffect) + .referralCode(resultSet.getString("referralCode")) + .tenantId(resultSet.getString("tenantid")) + .reasons(resultSet.getString("reasons") == null ? null : objectMapper.readValue(resultSet.getString("reasons"), ArrayList.class)) + .build(); + } catch (JsonProcessingException e) { + // Wrap JsonProcessingException into RuntimeException + throw new RuntimeException(e); + } + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java new file mode 100644 index 00000000000..3832d8bd7e3 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java @@ -0,0 +1,73 @@ +package org.egov.referralmanagement.repository.rowmapper; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import org.egov.common.models.core.AdditionalFields; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +@Component +public class SideEffectRowMapper implements RowMapper { + + @Autowired + ObjectMapper objectMapper; + + /** + * Maps a row of the ResultSet to a SideEffect object. + * + * @param resultSet the ResultSet containing the data from the database + * @param i the current row number + * @return a SideEffect object mapped from the ResultSet + * @throws SQLException if an SQL exception occurs + */ + @Override + public SideEffect mapRow(ResultSet resultSet, int i) throws SQLException { + try { + // Mapping AuditDetails + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + + // Mapping client AuditDetails + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("clientCreatedBy")) + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build(); + + // Building SideEffect object + return SideEffect.builder() + .id(resultSet.getString("id")) + .rowVersion(resultSet.getInt("rowversion")) + .isDeleted(resultSet.getBoolean("isdeleted")) + .auditDetails(auditDetails) + .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper + .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) + .clientAuditDetails(clientAuditDetails) + .clientReferenceId(resultSet.getString("clientreferenceid")) + .taskId(resultSet.getString("taskId")) + .taskClientReferenceId(resultSet.getString("taskClientreferenceid")) + .projectBeneficiaryId(resultSet.getString("projectBeneficiaryId")) + .projectBeneficiaryClientReferenceId(resultSet.getString("projectBeneficiaryClientReferenceId")) + .tenantId(resultSet.getString("tenantid")) + // Deserializing JSON array stored in the 'symptoms' column to ArrayList + .symptoms(resultSet.getString("symptoms") == null ? null : + objectMapper.readValue(resultSet.getString("symptoms"), ArrayList.class)) + .build(); + } catch (JsonProcessingException e) { + // Wrapping JsonProcessingException into SQLException + throw new SQLException(e); + } + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java new file mode 100644 index 00000000000..7db34924dd4 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java @@ -0,0 +1,489 @@ +package org.egov.referralmanagement.service; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.household.Household; +import org.egov.common.models.household.HouseholdBulkResponse; +import org.egov.common.models.household.HouseholdMember; +import org.egov.common.models.household.HouseholdMemberBulkResponse; +import org.egov.common.models.household.HouseholdMemberSearch; +import org.egov.common.models.household.HouseholdMemberSearchRequest; +import org.egov.common.models.household.HouseholdSearch; +import org.egov.common.models.household.HouseholdSearchRequest; +import org.egov.common.models.individual.Individual; +import org.egov.common.models.individual.IndividualBulkResponse; +import org.egov.common.models.individual.IndividualSearch; +import org.egov.common.models.individual.IndividualSearchRequest; +import org.egov.common.models.project.BeneficiaryBulkResponse; +import org.egov.common.models.project.BeneficiarySearchRequest; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.models.project.ProjectBeneficiarySearch; +import org.egov.common.models.project.Task; +import org.egov.common.models.project.TaskBulkResponse; +import org.egov.common.models.project.TaskSearch; +import org.egov.common.models.project.TaskSearchRequest; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralSearch; +import org.egov.common.models.referralmanagement.ReferralSearchRequest; +import org.egov.common.models.referralmanagement.beneficiarydownsync.Downsync; +import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncCriteria; +import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +@Service +@Slf4j +public class DownsyncService { + + private ServiceRequestClient restClient; + + private ReferralManagementConfiguration configs; + + private NamedParameterJdbcTemplate jdbcTemplate; + + private SideEffectService sideEffectService; + + private ReferralManagementService referralService; + + private MasterDataService masterDataService; + + @Autowired + public DownsyncService( ServiceRequestClient serviceRequestClient, + ReferralManagementConfiguration referralManagementConfiguration, + NamedParameterJdbcTemplate jdbcTemplate, + SideEffectService sideEffectService, + ReferralManagementService referralService, + MasterDataService masterDataService ) { + + this.restClient = serviceRequestClient; + this.configs = referralManagementConfiguration; + this.jdbcTemplate = jdbcTemplate; + this.sideEffectService=sideEffectService; + this.referralService=referralService; + this.masterDataService=masterDataService; + + } + + /** + * + * @param downsyncRequest + * @return Downsync + */ + public Downsync prepareDownsyncData(DownsyncRequest downsyncRequest) { + + Downsync downsync = new Downsync(); + DownsyncCriteria downsyncCriteria = downsyncRequest.getDownsyncCriteria(); + + List householdIds = null; + Set individualIds = null; + List individualClientRefIds = null; + List beneficiaryClientRefIds = null; + List taskClientRefIds = null; + + + downsync.setDownsyncCriteria(downsyncCriteria); + boolean isSyncTimeAvailable = null != downsyncCriteria.getLastSyncedTime(); + + //Project project = getProjectType(downsyncRequest); + LinkedHashMap projectType = masterDataService.getProjectType(downsyncRequest); + + /* search household */ + householdIds = searchHouseholds(downsyncRequest, downsync); + + /* search household member using household ids */ + if (isSyncTimeAvailable || !CollectionUtils.isEmpty(householdIds)) { + individualIds = searchMembers(downsyncRequest, downsync, householdIds); + } + + /* search individuals using individual ids */ + if (isSyncTimeAvailable || !CollectionUtils.isEmpty(individualIds) ) { + individualClientRefIds = searchIndividuals(downsyncRequest, downsync, individualIds); + } + + /* search beneficiary using individual ids OR household ids */ + + String beneficiaryType = (String) projectType.get("beneficiaryType"); + + beneficiaryClientRefIds = individualClientRefIds; + + if("HOUSEHOLD".equalsIgnoreCase(beneficiaryType)) + beneficiaryClientRefIds = downsync.getHouseholds().stream().map(Household::getClientReferenceId).collect(Collectors.toList()); + + //fetch beneficiary in the db + if (isSyncTimeAvailable || !CollectionUtils.isEmpty(beneficiaryClientRefIds)) { + beneficiaryClientRefIds = searchBeneficiaries(downsyncRequest, downsync, beneficiaryClientRefIds); + } + + /* search tasks using beneficiary uuids */ + if (isSyncTimeAvailable || !CollectionUtils.isEmpty(beneficiaryClientRefIds)) { + + taskClientRefIds = searchTasks(downsyncRequest, downsync, beneficiaryClientRefIds, projectType); + + /* ref search */ + referralSearch(downsyncRequest, downsync, beneficiaryClientRefIds); + } + + + if (isSyncTimeAvailable || !CollectionUtils.isEmpty(taskClientRefIds)) { + searchSideEffect(downsyncRequest, downsync, taskClientRefIds); + } + + return downsync; + } + + + /** + * + * @param downsyncRequest + * @param downsync + * @return + */ + private List searchHouseholds(DownsyncRequest downsyncRequest, Downsync downsync) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + + StringBuilder householdUrl = new StringBuilder(configs.getHouseholdHost()) + .append(configs.getHouseholdSearchUrl()); + householdUrl = appendUrlParams(householdUrl, criteria, null, null, true); + + HouseholdSearch householdSearch = HouseholdSearch.builder() + .localityCode(criteria.getLocality()) + .build(); + + HouseholdSearchRequest searchRequest = HouseholdSearchRequest.builder() + .household(householdSearch) + .requestInfo(requestInfo) + .build(); + + HouseholdBulkResponse res = restClient.fetchResult(householdUrl, searchRequest, HouseholdBulkResponse.class); + List households = res.getHouseholds(); + downsync.setHouseholds(households); + downsync.getDownsyncCriteria().setTotalCount(res.getTotalCount()); + + if(CollectionUtils.isEmpty(households)) + return Collections.emptyList(); + + return households.stream().map(Household::getId).collect(Collectors.toList()); + } + + /** + * + * @param downsyncRequest + * @param downsync + * @param individualIds + * @return individual ClientReferenceIds + */ + private List searchIndividuals(DownsyncRequest downsyncRequest, Downsync downsync, + Set individualIds) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + + StringBuilder url = new StringBuilder(configs.getIndividualHost()) + .append(configs.getIndividualSearchUrl()); + + url = appendUrlParams(url, criteria, 0, individualIds.size(),true); + + IndividualSearch individualSearch = IndividualSearch.builder() + .build(); + + if(!CollectionUtils.isEmpty(individualIds)) + individualSearch.setId(new ArrayList<>(individualIds)); + + IndividualSearchRequest searchRequest = IndividualSearchRequest.builder() + .individual(individualSearch) + .requestInfo(requestInfo) + .build(); + + List individuals = restClient.fetchResult(url, searchRequest, IndividualBulkResponse.class).getIndividual(); + downsync.setIndividuals(individuals); + + return individuals.stream().map(Individual::getClientReferenceId).collect(Collectors.toList()); + } + + /** + * + * @param downsyncRequest + * @param householdIds + * @return + */ + private Set searchMembers(DownsyncRequest downsyncRequest, Downsync downsync, + List householdIds) { + + Long lastChangedSince = downsyncRequest.getDownsyncCriteria().getLastSyncedTime(); + + List memberids = getPrimaryIds(householdIds, "householdId","HOUSEHOLD_MEMBER",lastChangedSince); + + if (CollectionUtils.isEmpty(memberids)) + return Collections.emptySet(); + + StringBuilder memberUrl = new StringBuilder(configs.getHouseholdHost()) + .append(configs.getHouseholdMemberSearchUrl()); + + appendUrlParams(memberUrl, downsyncRequest.getDownsyncCriteria(), 0, householdIds.size(), false); + + HouseholdMemberSearch memberSearch = HouseholdMemberSearch.builder() + .id(memberids) + .build(); + + HouseholdMemberSearchRequest searchRequest = HouseholdMemberSearchRequest.builder() + .householdMemberSearch(memberSearch) + .requestInfo(downsyncRequest.getRequestInfo()) + .build(); + + List members = restClient.fetchResult(memberUrl, searchRequest, HouseholdMemberBulkResponse.class).getHouseholdMembers(); + downsync.setHouseholdMembers(members); + + return members.stream().map(HouseholdMember::getIndividualId).collect(Collectors.toSet()); + } + + /** + * + * @param downsyncRequest + * @param downsync + * @param beneficiaryClientRefIds + * @return clientreferenceid of beneficiary object + */ + private List searchBeneficiaries(DownsyncRequest downsyncRequest, Downsync downsync, + List beneficiaryClientRefIds) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + Long lastChangedSince =criteria.getLastSyncedTime(); + + List beneficiaryIds = getPrimaryIds( + beneficiaryClientRefIds, + "beneficiaryclientreferenceid", + "PROJECT_BENEFICIARY", + lastChangedSince + ); + + if(CollectionUtils.isEmpty(beneficiaryIds)) + return Collections.emptyList(); + + StringBuilder url = new StringBuilder(configs.getProjectHost()) + .append(configs.getProjectBeneficiarySearchUrl()); + + url = appendUrlParams(url, criteria, 0, beneficiaryClientRefIds.size(),false); + + ProjectBeneficiarySearch search = ProjectBeneficiarySearch.builder() + .id(beneficiaryIds) + .projectId(Collections.singletonList(downsyncRequest.getDownsyncCriteria().getProjectId())) + .build(); + + BeneficiarySearchRequest searchRequest = BeneficiarySearchRequest.builder() + .projectBeneficiary(search) + .requestInfo(requestInfo) + .build(); + + List beneficiaries = restClient.fetchResult(url, searchRequest, BeneficiaryBulkResponse.class).getProjectBeneficiaries(); + downsync.setProjectBeneficiaries(beneficiaries); + + return beneficiaries.stream().map(ProjectBeneficiary::getClientReferenceId).collect(Collectors.toList()); + } + + + + /** + * + * @param downsyncRequest + * @param downsync + * @param beneficiaryClientRefIds + * @param projectType + * @return + */ + private List searchTasks(DownsyncRequest downsyncRequest, Downsync downsync, + List beneficiaryClientRefIds, LinkedHashMap projectType) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + List taskIds = getPrimaryIds(beneficiaryClientRefIds, "projectBeneficiaryClientReferenceId", "PROJECT_TASK", + criteria.getLastSyncedTime()); + + if(CollectionUtils.isEmpty(taskIds)) + return Collections.emptyList(); + + StringBuilder url = new StringBuilder(configs.getProjectHost()) + .append(configs.getProjectTaskSearchUrl()); + + url = appendUrlParams(url, criteria, 0, taskIds.size(), false); + + TaskSearch search = TaskSearch.builder() + .id(taskIds) + .projectId(Collections.singletonList(downsyncRequest.getDownsyncCriteria().getProjectId())) + .build(); + + TaskSearchRequest searchRequest = TaskSearchRequest.builder() + .task(search) + .requestInfo(requestInfo) + .build(); + + List tasks = restClient.fetchResult(url, searchRequest, TaskBulkResponse.class).getTasks(); + downsync.setTasks(tasks); + + return tasks.stream().map(Task::getClientReferenceId).collect(Collectors.toList()); + } + + /** + * + * @param downsyncRequest + * @param downsync + * @param taskClientRefIds + */ + private void searchSideEffect(DownsyncRequest downsyncRequest, Downsync downsync, + List taskClientRefIds) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + + /* FIXME SHOULD BE REMOVED AND TASK SEARCH SHOULD BE enhanced with list of client-ref-beneficiary ids*/ + List SEIds = getPrimaryIds(taskClientRefIds, "taskClientReferenceId", "SIDE_EFFECT", criteria.getLastSyncedTime()); + + if(CollectionUtils.isEmpty(SEIds)) + return; + + SideEffectSearch search = SideEffectSearch.builder() + .id(SEIds) + .build(); + + SideEffectSearchRequest effectSearchRequest = SideEffectSearchRequest.builder() + .sideEffect(search) + .requestInfo(requestInfo) + .build(); + + List effects = sideEffectService.search( + effectSearchRequest, + SEIds.size(), + 0, + criteria.getTenantId(), + criteria.getLastSyncedTime(), + criteria.getIncludeDeleted() + ).getResponse(); + + downsync.setSideEffects(effects); + } + + private void referralSearch(DownsyncRequest downsyncRequest, Downsync downsync, + List beneficiaryClientRefIds) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + Integer limit = beneficiaryClientRefIds.size(); + + ReferralSearch search = ReferralSearch.builder() + .build(); + + if(!CollectionUtils.isEmpty(beneficiaryClientRefIds)) { + search.setProjectBeneficiaryClientReferenceId(beneficiaryClientRefIds); + limit = null; + } + + ReferralSearchRequest searchRequest = ReferralSearchRequest.builder() + .referral(search) + .requestInfo(requestInfo) + .build(); + + List referrals = referralService.search( + searchRequest, + limit, + 0, + criteria.getTenantId(), + criteria.getLastSyncedTime(), + criteria.getIncludeDeleted() + ).getResponse(); + + downsync.setReferrals(referrals); + } + + + /** + * common method to fetch Ids with list of relation Ids like id of member with householdIds + * @param idList + * @param idListFieldName + * @param tableName + * @param lastChangedSince + * @return + */ + private List getPrimaryIds(List idList, String idListFieldName, String tableName, Long lastChangedSince) { + + /** + * Adding lastShangedSince to id query to avoid load on API search for members + */ + boolean isAndRequired = false; + Map paramMap = new HashMap<>(); + StringBuilder memberIdsquery = new StringBuilder("SELECT id from %s WHERE "); + + + if (!CollectionUtils.isEmpty(idList)) { + + memberIdsquery.append("%s IN (:%s)"); + paramMap.put(idListFieldName, idList); + isAndRequired = true; + } + + if (null != lastChangedSince) { + if(isAndRequired) + memberIdsquery.append(" AND "); + memberIdsquery.append(" lastModifiedTime >= (:lastChangedSince)"); + paramMap.put("lastChangedSince", lastChangedSince); + } + + String finalQuery = String.format(memberIdsquery.toString(), tableName, idListFieldName, idListFieldName); + /* FIXME SHOULD BE REMOVED AND SEARCH SHOULD BE enhanced with list of household ids*/ + List memberids = jdbcTemplate.queryForList(finalQuery, paramMap, String.class); + return memberids; + } + + /** + * append url params + * + * @param url + * @param criteria + * @param offset + * @param limit + * @param sendPrevSyncTime + * @return + */ + private StringBuilder appendUrlParams(StringBuilder url, DownsyncCriteria criteria, Integer offset, Integer limit, boolean sendPrevSyncTime) { + + url.append("?tenantId=") + .append(criteria.getTenantId()) + .append("&includeDeleted=") + .append(criteria.getIncludeDeleted()) + .append("&limit="); + + if (null != limit && limit != 0) + url.append(limit); + else + url.append(criteria.getLimit()); + + url.append("&offset="); + + if(null != offset) + url.append(offset); + else + url.append(criteria.getOffset()); + + if(sendPrevSyncTime && null != criteria.getLastSyncedTime()) + url.append("&lastChangedSince=").append(criteria.getLastSyncedTime()); + + return url; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/FacilityService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/FacilityService.java new file mode 100644 index 00000000000..993dca6757d --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/FacilityService.java @@ -0,0 +1,92 @@ +package org.egov.referralmanagement.service; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.facility.Facility; +import org.egov.common.models.facility.FacilityBulkResponse; +import org.egov.common.models.facility.FacilitySearch; +import org.egov.common.models.facility.FacilitySearchRequest; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForEntityWithNetworkError; + +/** + * Facility Service that validates facility IDs using an API call. + */ +@Service +@Slf4j +public class FacilityService { + + private final ReferralManagementConfiguration referralManagementConfiguration; + + private final ServiceRequestClient serviceRequestClient; + + @Autowired + public FacilityService(ReferralManagementConfiguration referralManagementConfiguration, ServiceRequestClient serviceRequestClient) { + this.referralManagementConfiguration = referralManagementConfiguration; + this.serviceRequestClient = serviceRequestClient; + } + + /** + * Validate a list of facility IDs by making an API call. + * + * @param entityIds List of facility IDs to validate. + * @param entities List of entities associated with the facility IDs. + * @param tenantId Tenant ID for filtering facilities. + * @param errorDetailsMap A map to store error details for each entity. + * @param requestInfo Request information for the API call. + * @return List of valid facility IDs. + */ + public List validateFacilityIds(List entityIds, + List entities, + String tenantId, + Map> errorDetailsMap, + RequestInfo requestInfo) { + // Check if the entityIds list is empty, return an empty list if so. + if (CollectionUtils.isEmpty(entityIds)) + return Collections.emptyList(); + + // Create a FacilitySearchRequest to fetch facility information for the given IDs. + FacilitySearchRequest facilitySearchRequest = FacilitySearchRequest.builder() + .facility(FacilitySearch.builder().id(entityIds).build()) + .requestInfo(requestInfo) + .build(); + + try { + // Make an API call to fetch facilities based on entity IDs. + FacilityBulkResponse response = serviceRequestClient.fetchResult( + new StringBuilder(referralManagementConfiguration.getFacilityHost()) + .append(referralManagementConfiguration.getFacilitySearchUrl()) + .append("?limit=").append(entityIds.size()) + .append("&offset=0&tenantId=").append(tenantId), + facilitySearchRequest, + FacilityBulkResponse.class); + + // Extract and return valid facility IDs from the response. + return response.getFacilities().stream().map(Facility::getId).collect(Collectors.toList()); + } catch (Exception e) { + log.error("error while fetching facility list: {}", ExceptionUtils.getStackTrace(e)); + + // Handle errors by associating errors with the respective entities. + entities.forEach( entity -> { + Error error = getErrorForEntityWithNetworkError(); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + + // Return an empty list in case of an error. + return Collections.emptyList(); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java new file mode 100644 index 00000000000..c3c287bcff3 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java @@ -0,0 +1,265 @@ +package org.egov.referralmanagement.service; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.ds.Tuple; +import org.egov.common.models.ErrorDetails; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralRequest; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralSearchRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.Constants; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.repository.HFReferralRepository; +import org.egov.referralmanagement.service.enrichment.HFReferralEnrichmentService; +import org.egov.referralmanagement.validator.hfreferral.HfrExistentEntityValidator; +import org.egov.referralmanagement.validator.hfreferral.HfrIsDeletedValidator; +import org.egov.referralmanagement.validator.hfreferral.HfrNonExistentEntityValidator; +import org.egov.referralmanagement.validator.hfreferral.HfrNullIdValidator; +import org.egov.referralmanagement.validator.hfreferral.HfrProjectFacilityIdValidator; +import org.egov.referralmanagement.validator.hfreferral.HfrProjectIdValidator; +import org.egov.referralmanagement.validator.hfreferral.HfrRowVersionValidator; +import org.egov.referralmanagement.validator.hfreferral.HfrUniqueEntityValidator; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Service; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +/** + * Service class for handling operations related to HFReferral entities. + * Manages creation, updating, searching, and deletion of HFReferrals. + * Includes validation and enrichment of HFReferrals before interacting with the repository. + * Author: kanishq-egov + */ +@Service +@Slf4j +public class HFReferralService { + + private final IdGenService idGenService; + private final HFReferralRepository hfReferralRepository; + private final ReferralManagementConfiguration referralManagementConfiguration; + private final HFReferralEnrichmentService hfReferralEnrichmentService; + private final List> validators; + + // Predicates to determine which validators are applicable for create, update, and delete operations + private final Predicate> isApplicableForCreate = validator -> + validator.getClass().equals(HfrProjectIdValidator.class) + || validator.getClass().equals(HfrExistentEntityValidator.class) + || validator.getClass().equals(HfrProjectFacilityIdValidator.class); + + private final Predicate> isApplicableForUpdate = validator -> + validator.getClass().equals(HfrProjectIdValidator.class) + || validator.getClass().equals(HfrProjectFacilityIdValidator.class) + || validator.getClass().equals(HfrNullIdValidator.class) + || validator.getClass().equals(HfrIsDeletedValidator.class) + || validator.getClass().equals(HfrUniqueEntityValidator.class) + || validator.getClass().equals(HfrNonExistentEntityValidator.class) + || validator.getClass().equals(HfrRowVersionValidator.class); + + private final Predicate> isApplicableForDelete = validator -> + validator.getClass().equals(HfrNullIdValidator.class) + || validator.getClass().equals(HfrNonExistentEntityValidator.class) + || validator.getClass().equals(HfrRowVersionValidator.class); + + /** + * Constructor to initialize the service with required dependencies. + * + * @param idGenService The IdGenService for generating IDs. + * @param hfReferralRepository The repository for HFReferral entities. + * @param referralManagementConfiguration The configuration for referral management. + * @param hfReferralEnrichmentService The service for enriching HFReferral entities. + * @param validators The list of validators for HFReferral entities. + */ + public HFReferralService(IdGenService idGenService, HFReferralRepository hfReferralRepository, + ReferralManagementConfiguration referralManagementConfiguration, + HFReferralEnrichmentService hfReferralEnrichmentService, + List> validators) { + this.idGenService = idGenService; + this.hfReferralRepository = hfReferralRepository; + this.referralManagementConfiguration = referralManagementConfiguration; + this.hfReferralEnrichmentService = hfReferralEnrichmentService; + this.validators = validators; + } + + // Method to create a single HFReferral + public HFReferral create(HFReferralRequest request) { + log.info("Received request to create a referral"); + HFReferralBulkRequest bulkRequest = HFReferralBulkRequest.builder().requestInfo(request.getRequestInfo()) + .hfReferrals(Collections.singletonList(request.getHfReferral())).build(); + log.info("Creating bulk request"); + return create(bulkRequest, false).get(0); + } + + // Method to create multiple HFReferrals in bulk + public List create(HFReferralBulkRequest hfReferralRequest, boolean isBulk) { + log.info("Received request to create bulk referrals"); + Tuple, Map> tuple = validate(validators, + isApplicableForCreate, hfReferralRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validReferrals = tuple.getX(); + + try { + if (!validReferrals.isEmpty()) { + log.info("Processing {} valid entities", validReferrals.size()); + hfReferralEnrichmentService.create(validReferrals, hfReferralRequest); + hfReferralRepository.save(validReferrals, + referralManagementConfiguration.getCreateHFReferralTopic()); + log.info("Successfully created referrals"); + } + } catch (Exception exception) { + log.error("Error occurred while creating referrals: {}", exception.getMessage()); + populateErrorDetails(hfReferralRequest, errorDetailsMap, validReferrals, + exception, Constants.SET_HF_REFERRALS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validReferrals; + } + + // Method to update a single HFReferral + public HFReferral update(HFReferralRequest request) { + log.info("Received request to update a referral"); + HFReferralBulkRequest bulkRequest = HFReferralBulkRequest.builder().requestInfo(request.getRequestInfo()) + .hfReferrals(Collections.singletonList(request.getHfReferral())).build(); + log.info("Creating bulk request"); + return update(bulkRequest, false).get(0); + } + + // Method to update multiple HFReferrals in bulk + public List update(HFReferralBulkRequest hfReferralRequest, boolean isBulk) { + log.info("Received request to update bulk referrals"); + Tuple, Map> tuple = validate(validators, + isApplicableForUpdate, hfReferralRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validReferrals = tuple.getX(); + + try { + if (!validReferrals.isEmpty()) { + log.info("Processing {} valid entities", validReferrals.size()); + hfReferralEnrichmentService.update(validReferrals, hfReferralRequest); + hfReferralRepository.save(validReferrals, + referralManagementConfiguration.getUpdateHFReferralTopic()); + log.info("Successfully updated bulk referrals"); + } + } catch (Exception exception) { + log.error("Error occurred while updating referrals", exception); + populateErrorDetails(hfReferralRequest, errorDetailsMap, validReferrals, + exception, Constants.SET_HF_REFERRALS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validReferrals; + } + + // Method to search for HFReferrals based on certain criteria + public List search(HFReferralSearchRequest referralSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) { + log.info("Received request to search referrals"); + String idFieldName = getIdFieldName(referralSearchRequest.getHfReferral()); + + // If searching by ID only, fetch referrals with specified IDs + if (isSearchByIdOnly(referralSearchRequest.getHfReferral(), idFieldName)) { + log.info("Searching referrals by ID"); + List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections + .singletonList(referralSearchRequest.getHfReferral())), + referralSearchRequest.getHfReferral()); + log.info("Fetching referrals with IDs: {}", ids); + + return hfReferralRepository.findById(ids, includeDeleted, idFieldName).stream() + .filter(lastChangedSince(lastChangedSince)) + .filter(havingTenantId(tenantId)) + .filter(includeDeleted(includeDeleted)) + .collect(Collectors.toList()); + } + + log.info("Searching referrals using criteria"); + return hfReferralRepository.find(referralSearchRequest.getHfReferral(), + limit, offset, tenantId, lastChangedSince, includeDeleted); + } + + // Method to delete a single HFReferral + public HFReferral delete(HFReferralRequest hfReferralRequest) { + log.info("Received request to delete a referral"); + HFReferralBulkRequest bulkRequest = HFReferralBulkRequest.builder().requestInfo(hfReferralRequest.getRequestInfo()) + .hfReferrals(Collections.singletonList(hfReferralRequest.getHfReferral())).build(); + log.info("Creating bulk request"); + return delete(bulkRequest, false).get(0); + } + + // Method to delete multiple HFReferrals in bulk + public List delete(HFReferralBulkRequest hfReferralRequest, boolean isBulk) { + Tuple, Map> tuple = validate(validators, + isApplicableForDelete, hfReferralRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validReferrals = tuple.getX(); + + try { + if (!validReferrals.isEmpty()) { + log.info("Processing {} valid entities", validReferrals.size()); + List referralIds = validReferrals.stream().map(entity -> entity.getId()).collect(Collectors.toSet()).stream().collect(Collectors.toList()); + List existingReferrals = hfReferralRepository + .findById(referralIds, false); + hfReferralEnrichmentService.delete(existingReferrals, hfReferralRequest); + hfReferralRepository.save(existingReferrals, + referralManagementConfiguration.getDeleteHFReferralTopic()); + log.info("Successfully deleted entities"); + } + } catch (Exception exception) { + log.error("Error occurred while deleting entities: {}", exception); + populateErrorDetails(hfReferralRequest, errorDetailsMap, validReferrals, + exception, Constants.SET_HF_REFERRALS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validReferrals; + } + + // Method to put HFReferrals in cache + public void putInCache(List hfReferrals) { + log.info("Putting {} HFReferrals in cache", hfReferrals.size()); + hfReferralRepository.putInCache(hfReferrals); + log.info("Successfully put HFReferrals in cache"); + } + + // Method to validate HFReferralBulkRequest + private Tuple, Map> validate( + List> validators, + Predicate> isApplicable, + HFReferralBulkRequest request, + boolean isBulk + ) { + log.info("Validating request"); + Map errorDetailsMap = CommonUtils.validate(validators, + isApplicable, request, + Constants.SET_HF_REFERRALS); + if (!errorDetailsMap.isEmpty() && !isBulk) { + log.error("Validation error occurred. Error details: {}", errorDetailsMap.values()); + throw new CustomException(Constants.VALIDATION_ERROR, errorDetailsMap.values().toString()); + } + List validReferrals = request.getHfReferrals().stream() + .filter(notHavingErrors()).collect(Collectors.toList()); + log.info("Validation successful, found valid referrals"); + return new Tuple<>(validReferrals, errorDetailsMap); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java new file mode 100644 index 00000000000..3c09df3edde --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java @@ -0,0 +1,129 @@ +package org.egov.referralmanagement.service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import com.jayway.jsonpath.JsonPath; +import digit.models.coremodels.mdms.MasterDetail; +import digit.models.coremodels.mdms.MdmsCriteria; +import digit.models.coremodels.mdms.MdmsCriteriaReq; +import digit.models.coremodels.mdms.ModuleDetail; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.project.Project; +import org.egov.common.models.project.ProjectRequest; +import org.egov.common.models.project.ProjectResponse; +import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncCriteria; +import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncRequest; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import static org.egov.referralmanagement.Constants.HCM_MASTER_PROJECTTYPE; +import static org.egov.referralmanagement.Constants.HCM_MDMS_PROJECTTYPE_RES_PATH; +import static org.egov.referralmanagement.Constants.HCM_MDMS_PROJECT_MODULE_NAME; +import static org.egov.referralmanagement.Constants.HCM_PROJECT_TYPE_FILTER_CODE; + +@Slf4j +@Service +public class MasterDataService { + + private ServiceRequestClient restClient; + + private ReferralManagementConfiguration configs; + + @Autowired + public MasterDataService(ServiceRequestClient serviceRequestClient, + ReferralManagementConfiguration referralManagementConfiguration) { + + this.restClient = serviceRequestClient; + this.configs = referralManagementConfiguration; + + } + + + @SuppressWarnings("unchecked") + public LinkedHashMap getProjectType(DownsyncRequest downsyncRequest) { + + DownsyncCriteria downsyncCriteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo info = downsyncRequest.getRequestInfo(); + String projectId = downsyncCriteria.getProjectId(); + + + Project project = getProject(downsyncCriteria, info, projectId); + + String projectCode = project.getProjectType(); // FIXME + + /* + * TODO FIXME code should get upgraded when next version of project is created with execution plan (project type master) in the additional details + */ + StringBuilder mdmsUrl = new StringBuilder(configs.getMdmsHost()) + .append(configs.getMdmsSearchUrl()); + + /* + * Assumption is that the project code is always unique + */ + MasterDetail masterDetail = MasterDetail.builder() + .name(HCM_MASTER_PROJECTTYPE) + .filter(String.format(HCM_PROJECT_TYPE_FILTER_CODE, projectCode)) // projectCode FIXME + .build(); + + ModuleDetail moduleDetail = ModuleDetail.builder() + .masterDetails(Arrays.asList(masterDetail)) + .moduleName(HCM_MDMS_PROJECT_MODULE_NAME) + .build(); + + MdmsCriteria mdmsCriteria = MdmsCriteria.builder() + .moduleDetails(Arrays.asList(moduleDetail)) + .tenantId(downsyncCriteria.getTenantId().split("//.")[0]) + .build(); + + MdmsCriteriaReq mdmsCriteriaReq = MdmsCriteriaReq.builder() + .mdmsCriteria(mdmsCriteria) + .requestInfo(info) + .build(); + + Map mdmsRes = restClient.fetchResult(mdmsUrl, mdmsCriteriaReq, HashMap.class); + List projectTypeRes = null; + try { + projectTypeRes = JsonPath.read(mdmsRes, HCM_MDMS_PROJECTTYPE_RES_PATH); + } catch (Exception e) { + log.error(e.getMessage()); + throw new CustomException("JSONPATH_ERROR", "Failed to parse mdms response"); + } + + return (LinkedHashMap) projectTypeRes.get(0); + + } + + + private Project getProject(DownsyncCriteria downsyncCriteria, RequestInfo info, String projectId) { + + StringBuilder url = new StringBuilder(configs.getProjectHost()) + .append(configs.getProjectSearchUrl()) + .append("?offset=0") + .append("&limit=100") + .append("&tenantId=").append(downsyncCriteria.getTenantId()); + + Project project = Project.builder() + .id(projectId) + .tenantId(downsyncCriteria.getTenantId()) + .build(); + + ProjectRequest projectRequest = ProjectRequest.builder() + .projects(Arrays.asList(project)) + .requestInfo(info) + .build(); + + ProjectResponse res = restClient.fetchResult(url, projectRequest, ProjectResponse.class); + return res.getProject().get(0); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java new file mode 100644 index 00000000000..38973d34e3c --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java @@ -0,0 +1,248 @@ +package org.egov.referralmanagement.service; + + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.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.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.referralmanagement.ReferralRequest; +import org.egov.common.models.referralmanagement.ReferralSearchRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.Constants; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.repository.ReferralRepository; +import org.egov.referralmanagement.service.enrichment.ReferralManagementEnrichmentService; +import org.egov.referralmanagement.validator.RmExistentEntityValidator; +import org.egov.referralmanagement.validator.RmIsDeletedValidator; +import org.egov.referralmanagement.validator.RmNonExistentEntityValidator; +import org.egov.referralmanagement.validator.RmNullIdValidator; +import org.egov.referralmanagement.validator.RmProjectBeneficiaryIdValidator; +import org.egov.referralmanagement.validator.RmRecipientIdValidator; +import org.egov.referralmanagement.validator.RmReferrerIdValidator; +import org.egov.referralmanagement.validator.RmRowVersionValidator; +import org.egov.referralmanagement.validator.RmSideEffectIdValidator; +import org.egov.referralmanagement.validator.RmUniqueEntityValidator; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Service; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +@Service +@Slf4j +public class ReferralManagementService { + + private final IdGenService idGenService; + + private final ReferralRepository referralRepository; + + private final ReferralManagementConfiguration referralManagementConfiguration; + + private final ReferralManagementEnrichmentService referralManagementEnrichmentService; + + private final List> validators; + + private final Predicate> isApplicableForCreate = validator -> + validator.getClass().equals(RmProjectBeneficiaryIdValidator.class) + || validator.getClass().equals(RmExistentEntityValidator.class) + || validator.getClass().equals(RmReferrerIdValidator.class) + || validator.getClass().equals(RmRecipientIdValidator.class) + || validator.getClass().equals(RmSideEffectIdValidator.class); + + private final Predicate> isApplicableForUpdate = validator -> + validator.getClass().equals(RmProjectBeneficiaryIdValidator.class) + || validator.getClass().equals(RmReferrerIdValidator.class) + || validator.getClass().equals(RmRecipientIdValidator.class) + || validator.getClass().equals(RmSideEffectIdValidator.class) + || validator.getClass().equals(RmNullIdValidator.class) + || validator.getClass().equals(RmIsDeletedValidator.class) + || validator.getClass().equals(RmUniqueEntityValidator.class) + || validator.getClass().equals(RmNonExistentEntityValidator.class) + || validator.getClass().equals(RmRowVersionValidator.class); + + private final Predicate> isApplicableForDelete = validator -> + validator.getClass().equals(RmNullIdValidator.class) + || validator.getClass().equals(RmNonExistentEntityValidator.class) + || validator.getClass().equals(RmRowVersionValidator.class); + + + public ReferralManagementService(IdGenService idGenService, ReferralRepository referralRepository, ReferralManagementConfiguration referralManagementConfiguration, ReferralManagementEnrichmentService referralManagementEnrichmentService, List> validators) { + this.idGenService = idGenService; + this.referralRepository = referralRepository; + this.referralManagementConfiguration = referralManagementConfiguration; + this.referralManagementEnrichmentService = referralManagementEnrichmentService; + this.validators = validators; + } + + public Referral create(ReferralRequest request) { + log.info("received request to create referrals"); + ReferralBulkRequest bulkRequest = ReferralBulkRequest.builder().requestInfo(request.getRequestInfo()) + .referrals(Collections.singletonList(request.getReferral())).build(); + log.info("creating bulk request"); + return create(bulkRequest, false).get(0); + } + + public List create(ReferralBulkRequest referralRequest, boolean isBulk) { + log.info("received request to create bulk referrals"); + Tuple, Map> tuple = validate(validators, + isApplicableForCreate, referralRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validReferrals = tuple.getX(); + + try { + if (!validReferrals.isEmpty()) { + log.info("processing {} valid entities", validReferrals.size()); + referralManagementEnrichmentService.create(validReferrals, referralRequest); + referralRepository.save(validReferrals, + referralManagementConfiguration.getCreateReferralTopic()); + log.info("successfully created referrals"); + } + } catch (Exception exception) { + log.error("error occurred while creating referrals: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, + exception, Constants.SET_REFERRALS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validReferrals; + } + + public Referral update(ReferralRequest request) { + log.info("received request to update referral"); + ReferralBulkRequest bulkRequest = ReferralBulkRequest.builder().requestInfo(request.getRequestInfo()) + .referrals(Collections.singletonList(request.getReferral())).build(); + log.info("creating bulk request"); + return update(bulkRequest, false).get(0); + } + + public List update(ReferralBulkRequest referralRequest, boolean isBulk) { + log.info("received request to update bulk referral"); + Tuple, Map> tuple = validate(validators, + isApplicableForUpdate, referralRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validReferrals = tuple.getX(); + + try { + if (!validReferrals.isEmpty()) { + log.info("processing {} valid entities", validReferrals.size()); + referralManagementEnrichmentService.update(validReferrals, referralRequest); + referralRepository.save(validReferrals, + referralManagementConfiguration.getUpdateReferralTopic()); + log.info("successfully updated bulk referrals"); + } + } catch (Exception exception) { + log.error("error occurred while updating referrals: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, + exception, Constants.SET_REFERRALS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validReferrals; + } + + public SearchResponse search(ReferralSearchRequest referralSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) { + log.info("received request to search referrals"); + String idFieldName = getIdFieldName(referralSearchRequest.getReferral()); + if (isSearchByIdOnly(referralSearchRequest.getReferral(), idFieldName)) { + log.info("searching referrals by id"); + List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections + .singletonList(referralSearchRequest.getReferral())), + referralSearchRequest.getReferral()); + log.info("fetching referrals with ids: {}", ids); + List referrals = referralRepository.findById(ids, idFieldName, includeDeleted).getResponse().stream() + .filter(lastChangedSince(lastChangedSince)) + .filter(havingTenantId(tenantId)) + .filter(includeDeleted(includeDeleted)) + .collect(Collectors.toList()); + return SearchResponse.builder().response(referrals).build(); + } + log.info("searching referrals using criteria"); + return referralRepository.find(referralSearchRequest.getReferral(), + limit, offset, tenantId, lastChangedSince, includeDeleted); + } + + public Referral delete(ReferralRequest referralRequest) { + log.info("received request to delete a referral"); + ReferralBulkRequest bulkRequest = ReferralBulkRequest.builder().requestInfo(referralRequest.getRequestInfo()) + .referrals(Collections.singletonList(referralRequest.getReferral())).build(); + log.info("creating bulk request"); + return delete(bulkRequest, false).get(0); + } + + public List delete(ReferralBulkRequest referralRequest, boolean isBulk) { + Tuple, Map> tuple = validate(validators, + isApplicableForDelete, referralRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validReferrals = tuple.getX(); + + try { + if (!validReferrals.isEmpty()) { + log.info("processing {} valid entities", validReferrals.size()); + List referralIds = validReferrals.stream().map(entity -> entity.getId()).collect(Collectors.toSet()).stream().collect(Collectors.toList()); + List existingReferrals = referralRepository + .findById(referralIds, false); + referralManagementEnrichmentService.delete(existingReferrals, referralRequest); + referralRepository.save(existingReferrals, + referralManagementConfiguration.getDeleteReferralTopic()); + log.info("successfully deleted entities"); + } + } catch (Exception exception) { + log.error("error occurred while deleting entities: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, + exception, Constants.SET_REFERRALS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validReferrals; + } + + public void putInCache(List referrals) { + log.info("putting {} referrals in cache", referrals.size()); + referralRepository.putInCache(referrals); + log.info("successfully put referrals in cache"); + } + + private Tuple, Map> validate( + List> validators, + Predicate> isApplicable, + ReferralBulkRequest request, + boolean isBulk + ) { + log.info("validating request"); + Map errorDetailsMap = CommonUtils.validate(validators, + isApplicable, request, + Constants.SET_REFERRALS); + if (!errorDetailsMap.isEmpty() && !isBulk) { + log.error("validation error occurred. error details: {}", errorDetailsMap.values().toString()); + throw new CustomException(Constants.VALIDATION_ERROR, errorDetailsMap.values().toString()); + } + List validReferrals = request.getReferrals().stream() + .filter(notHavingErrors()).collect(Collectors.toList()); + log.info("validation successful, found valid referrals"); + return new Tuple<>(validReferrals, errorDetailsMap); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java new file mode 100644 index 00000000000..c437e392fcf --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java @@ -0,0 +1,301 @@ +package org.egov.referralmanagement.service; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.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.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; +import org.egov.common.utils.CommonUtils; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.Constants; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.repository.SideEffectRepository; +import org.egov.referralmanagement.service.enrichment.SideEffectEnrichmentService; +import org.egov.referralmanagement.validator.sideeffect.SeExistentEntityValidator; +import org.egov.referralmanagement.validator.sideeffect.SeIsDeletedValidator; +import org.egov.referralmanagement.validator.sideeffect.SeNonExistentEntityValidator; +import org.egov.referralmanagement.validator.sideeffect.SeNullIdValidator; +import org.egov.referralmanagement.validator.sideeffect.SeProjectBeneficiaryIdValidator; +import org.egov.referralmanagement.validator.sideeffect.SeProjectTaskIdValidator; +import org.egov.referralmanagement.validator.sideeffect.SeRowVersionValidator; +import org.egov.referralmanagement.validator.sideeffect.SeUniqueEntityValidator; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +/** + * @author kanishq-egov + * Service created to enrich, validate request and perform crud operations + */ +@Service +@Slf4j +public class SideEffectService { + private final SideEffectRepository sideEffectRepository; + + private final ReferralManagementConfiguration referralManagementConfiguration; + + private final SideEffectEnrichmentService sideEffectEnrichmentService; + + private final List> validators; + + private final Predicate> isApplicableForCreate = validator -> + validator.getClass().equals(SeProjectTaskIdValidator.class) + || validator.getClass().equals(SeExistentEntityValidator.class) + || validator.getClass().equals(SeProjectBeneficiaryIdValidator.class); + + private final Predicate> isApplicableForUpdate = validator -> + validator.getClass().equals(SeProjectTaskIdValidator.class) + || validator.getClass().equals(SeNullIdValidator.class) + || validator.getClass().equals(SeIsDeletedValidator.class) + || validator.getClass().equals(SeUniqueEntityValidator.class) + || validator.getClass().equals(SeNonExistentEntityValidator.class) + || validator.getClass().equals(SeRowVersionValidator.class); + + private final Predicate> isApplicableForDelete = validator -> + validator.getClass().equals(SeNullIdValidator.class) + || validator.getClass().equals(SeNonExistentEntityValidator.class) + || validator.getClass().equals(SeRowVersionValidator.class); + + @Autowired + public SideEffectService( + SideEffectRepository sideEffectRepository, + ReferralManagementConfiguration referralManagementConfiguration, + SideEffectEnrichmentService sideEffectEnrichmentService, + List> validators + ) { + this.sideEffectRepository = sideEffectRepository; + this.referralManagementConfiguration = referralManagementConfiguration; + this.sideEffectEnrichmentService = sideEffectEnrichmentService; + this.validators = validators; + } + + /** + * converting SideEffectRequest to SideEffectBulkRequest + * @param request + * @return + */ + public SideEffect create(SideEffectRequest request) { + log.info("received request to create side effects"); + SideEffectBulkRequest bulkRequest = SideEffectBulkRequest.builder().requestInfo(request.getRequestInfo()) + .sideEffects(Collections.singletonList(request.getSideEffect())).build(); + log.info("creating bulk request"); + return create(bulkRequest, false).get(0); + } + + /** + * validate the request, for valid objects after enriching them, sending it to kafka, and + * throwing error for the invalid objects. + * @param sideEffectRequest + * @param isBulk + * @return + */ + public List create(SideEffectBulkRequest sideEffectRequest, boolean isBulk) { + log.info("received request to create bulk side effects"); + Tuple, Map> tuple = validate(validators, + isApplicableForCreate, sideEffectRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validSideEffects = tuple.getX(); + + try { + if (!validSideEffects.isEmpty()) { + log.info("processing {} valid entities", validSideEffects.size()); + sideEffectEnrichmentService.create(validSideEffects, sideEffectRequest); + sideEffectRepository.save(validSideEffects, + referralManagementConfiguration.getCreateSideEffectTopic()); + log.info("successfully created side effects"); + } + } catch (Exception exception) { + log.error("error occurred while creating side effects: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(sideEffectRequest, errorDetailsMap, validSideEffects, + exception, Constants.SET_SIDE_EFFECTS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validSideEffects; + } + + /** + * converting SideEffectRequest to SideEffectBulkRequest + * @param request + * @return + */ + public SideEffect update(SideEffectRequest request) { + log.info("received request to update side effect"); + SideEffectBulkRequest bulkRequest = SideEffectBulkRequest.builder().requestInfo(request.getRequestInfo()) + .sideEffects(Collections.singletonList(request.getSideEffect())).build(); + log.info("creating bulk request"); + return update(bulkRequest, false).get(0); + } + + /** + * validate the request, for valid objects after enriching them, sending it to kafka, and + * throwing error for the invalid objects. + * @param sideEffectRequest + * @param isBulk + * @return + */ + public List update(SideEffectBulkRequest sideEffectRequest, boolean isBulk) { + log.info("received request to update bulk side effect"); + Tuple, Map> tuple = validate(validators, + isApplicableForUpdate, sideEffectRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validSideEffects = tuple.getX(); + + try { + if (!validSideEffects.isEmpty()) { + log.info("processing {} valid entities", validSideEffects.size()); + sideEffectEnrichmentService.update(validSideEffects, sideEffectRequest); + sideEffectRepository.save(validSideEffects, + referralManagementConfiguration.getUpdateSideEffectTopic()); + log.info("successfully updated bulk side effects"); + } + } catch (Exception exception) { + log.error("error occurred while updating side effects: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(sideEffectRequest, errorDetailsMap, validSideEffects, + exception, Constants.SET_SIDE_EFFECTS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validSideEffects; + } + + /** + * searching based on parameters + * @param sideEffectSearchRequest + * @param limit + * @param offset + * @param tenantId + * @param lastChangedSince + * @param includeDeleted + * @return + * @throws Exception + */ + public SearchResponse search(SideEffectSearchRequest sideEffectSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) { + log.info("received request to search side effects"); + String idFieldName = getIdFieldName(sideEffectSearchRequest.getSideEffect()); + if (isSearchByIdOnly(sideEffectSearchRequest.getSideEffect(), idFieldName)) { + log.info("searching side effects by id"); + List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections + .singletonList(sideEffectSearchRequest.getSideEffect())), + sideEffectSearchRequest.getSideEffect()); + log.info("fetching side effects with ids: {}", ids); + List sideEffectList = sideEffectRepository.findById(ids, includeDeleted, idFieldName); + return SearchResponse.builder().response(sideEffectList.stream() + .filter(lastChangedSince(lastChangedSince)) + .filter(havingTenantId(tenantId)) + .filter(includeDeleted(includeDeleted)) + .collect(Collectors.toList())).build(); + } + log.info("searching side effects using criteria"); + return sideEffectRepository.find(sideEffectSearchRequest.getSideEffect(), + limit, offset, tenantId, lastChangedSince, includeDeleted); + } + + /** + * converting SideEffectRequest to SideEffectBulkRequest + * @param sideEffectRequest + * @return + */ + public SideEffect delete(SideEffectRequest sideEffectRequest) { + log.info("received request to delete a side effect"); + SideEffectBulkRequest bulkRequest = SideEffectBulkRequest.builder().requestInfo(sideEffectRequest.getRequestInfo()) + .sideEffects(Collections.singletonList(sideEffectRequest.getSideEffect())).build(); + log.info("creating bulk request"); + return delete(bulkRequest, false).get(0); + } + + /** + * validating the request, enriching the valid objects and sending them to kafka + * throwing error on invalid objects + * @param sideEffectRequest + * @param isBulk + * @return + */ + public List delete(SideEffectBulkRequest sideEffectRequest, boolean isBulk) { + Tuple, Map> tuple = validate(validators, + isApplicableForDelete, sideEffectRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validSideEffects = tuple.getX(); + + try { + if (!validSideEffects.isEmpty()) { + log.info("processing {} valid entities", validSideEffects.size()); + List sideEffectIds = validSideEffects.stream().map(entity -> entity.getId()).collect(Collectors.toSet()).stream().collect(Collectors.toList()); + List existingSideEffects = sideEffectRepository + .findById(sideEffectIds, false); + sideEffectEnrichmentService.delete(existingSideEffects, sideEffectRequest); + sideEffectRepository.save(existingSideEffects, + referralManagementConfiguration.getDeleteSideEffectTopic()); + log.info("successfully deleted entities"); + } + } catch (Exception exception) { + log.error("error occurred while deleting entities: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(sideEffectRequest, errorDetailsMap, validSideEffects, + exception, Constants.SET_SIDE_EFFECTS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validSideEffects; + } + + public void putInCache(List sideEffects) { + log.info("putting {} side effects in cache", sideEffects.size()); + sideEffectRepository.putInCache(sideEffects); + log.info("successfully put side effects in cache"); + } + + /** + * method use to valid request using parameters objects + * @param validators + * @param isApplicable + * @param request + * @param isBulk + * @return + */ + private Tuple, Map> validate( + List> validators, + Predicate> isApplicable, + SideEffectBulkRequest request, + boolean isBulk + ) { + log.info("validating request"); + Map errorDetailsMap = CommonUtils.validate(validators, + isApplicable, request, + Constants.SET_SIDE_EFFECTS); + if (!errorDetailsMap.isEmpty() && !isBulk) { + log.error("validation error occurred. error details: {}", errorDetailsMap.values().toString()); + throw new CustomException(Constants.VALIDATION_ERROR, errorDetailsMap.values().toString()); + } + List validSideEffects = request.getSideEffects().stream() + .filter(notHavingErrors()).collect(Collectors.toList()); + log.info("validation successful, found valid side effects"); + return new Tuple<>(validSideEffects, errorDetailsMap); + } + +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/HFReferralEnrichmentService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/HFReferralEnrichmentService.java new file mode 100644 index 00000000000..158b17c126d --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/HFReferralEnrichmentService.java @@ -0,0 +1,57 @@ +package org.egov.referralmanagement.service.enrichment; + +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.utils.CommonUtils; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.enrichForCreate; +import static org.egov.common.utils.CommonUtils.enrichForDelete; +import static org.egov.common.utils.CommonUtils.enrichForUpdate; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; + +@Component +@Slf4j +public class HFReferralEnrichmentService { + + /** + * + * @param entities + * @param request + */ + public void create(List entities, HFReferralBulkRequest request) { + log.info("starting the enrichment for create hfReferrals"); + log.info("generating IDs using UUID"); + List idList = CommonUtils.uuidSupplier().apply(entities.size()); + log.info("enriching referrals with generated IDs"); + enrichForCreate(entities, idList, request.getRequestInfo()); + log.info("enrichment done"); + } + + /** + * + * @param entities + * @param request + */ + public void update(List entities, HFReferralBulkRequest request) { + log.info("starting the enrichment for create hfReferrals"); + Map referralMap = getIdToObjMap(entities); + enrichForUpdate(referralMap, entities, request); + log.info("enrichment done"); + } + + /** + * + * @param entities + * @param request + */ + public void delete(List entities, HFReferralBulkRequest request) { + log.info("starting the enrichment for delete hfReferrals"); + enrichForDelete(entities, request.getRequestInfo(), true); + log.info("enrichment done"); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java new file mode 100644 index 00000000000..b0cd68a0cc9 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java @@ -0,0 +1,57 @@ +package org.egov.referralmanagement.service.enrichment; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.utils.CommonUtils; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +import static org.egov.common.utils.CommonUtils.enrichForCreate; +import static org.egov.common.utils.CommonUtils.enrichForDelete; +import static org.egov.common.utils.CommonUtils.enrichForUpdate; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; + +@Component +@Slf4j +public class ReferralManagementEnrichmentService { + + /** + * + * @param entities + * @param request + */ + public void create(List entities, ReferralBulkRequest request) { + log.info("starting the enrichment for create referrals"); + log.info("generating IDs using UUID"); + List idList = CommonUtils.uuidSupplier().apply(entities.size()); + log.info("enriching referrals with generated IDs"); + enrichForCreate(entities, idList, request.getRequestInfo()); + log.info("enrichment done"); + } + + /** + * + * @param entities + * @param request + */ + public void update(List entities, ReferralBulkRequest request) { + log.info("starting the enrichment for create referrals"); + Map referralMap = getIdToObjMap(entities); + enrichForUpdate(referralMap, entities, request); + log.info("enrichment done"); + } + + /** + * + * @param entities + * @param request + */ + public void delete(List entities, ReferralBulkRequest request) { + log.info("starting the enrichment for delete referrals"); + enrichForDelete(entities, request.getRequestInfo(), true); + log.info("enrichment done"); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/SideEffectEnrichmentService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/SideEffectEnrichmentService.java new file mode 100644 index 00000000000..03eefb43298 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/SideEffectEnrichmentService.java @@ -0,0 +1,60 @@ +package org.egov.referralmanagement.service.enrichment; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.utils.CommonUtils; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +import static org.egov.common.utils.CommonUtils.enrichForCreate; +import static org.egov.common.utils.CommonUtils.enrichForDelete; +import static org.egov.common.utils.CommonUtils.enrichForUpdate; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; + +/** + * Class use to enrich SideEffectBulkRequest object + */ +@Component +@Slf4j +public class SideEffectEnrichmentService { + + /** + * + * @param entities + * @param request + */ + public void create(List entities, SideEffectBulkRequest request) { + log.info("starting the enrichment for create side effect"); + log.info("generating IDs using UUID"); + List idList = CommonUtils.uuidSupplier().apply(entities.size()); + log.info("enriching side effects with generated IDs"); + enrichForCreate(entities, idList, request.getRequestInfo()); + log.info("enrichment done"); + } + + /** + * + * @param entities + * @param request + */ + public void update(List entities, SideEffectBulkRequest request) { + log.info("starting the enrichment for create side effect"); + Map sideEffectMap = getIdToObjMap(entities); + enrichForUpdate(sideEffectMap, entities, request); + log.info("enrichment done"); + } + + /** + * + * @param entities + * @param request + */ + public void delete(List entities, SideEffectBulkRequest request) { + log.info("starting the enrichment for delete side effect"); + enrichForDelete(entities, request.getRequestInfo(), true); + log.info("enrichment done"); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/util/ValidatorUtil.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/util/ValidatorUtil.java new file mode 100644 index 00000000000..043c7d6a1b5 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/util/ValidatorUtil.java @@ -0,0 +1,34 @@ +package org.egov.referralmanagement.util; + +import digit.models.coremodels.UserSearchRequest; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.service.UserService; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * A Validation helper Util + */ +public class ValidatorUtil { + + /** + * validate and remove valid identifiers from invalidStaffIds + * @param requestInfo + * @param userService + * @param staffIds + * @param invalidStaffIds + */ + public static void validateAndEnrichStaffIds(RequestInfo requestInfo, UserService userService, + List staffIds, List invalidStaffIds) { + if (!CollectionUtils.isEmpty(staffIds)) { + UserSearchRequest userSearchRequest = new UserSearchRequest(); + userSearchRequest.setRequestInfo(requestInfo); + userSearchRequest.setUuid(staffIds); + List validStaffIds = userService.search(userSearchRequest).stream().map(user -> user.getUuid()) + .collect(Collectors.toList()); + invalidStaffIds.removeAll(validStaffIds); + } + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmExistentEntityValidator.java new file mode 100644 index 00000000000..c12c03054ef --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmExistentEntityValidator.java @@ -0,0 +1,94 @@ +package org.egov.referralmanagement.validator; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.referralmanagement.ReferralSearch; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.repository.ReferralRepository; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of referral entities with the given client reference IDs. + * This validator checks if the provided Referral entities already exist in the database based on their client reference IDs. + * + * @author kanishq-egov + */ +@Component +@Order(value = 1) +@Slf4j +public class RmExistentEntityValidator implements Validator { + + private final ReferralRepository referralRepository; + + /** + * Constructor to initialize the ReferralRepository dependency. + * + * @param referralRepository The repository used to validate referral entities. + */ + public RmExistentEntityValidator(ReferralRepository referralRepository) { + this.referralRepository = referralRepository; + } + + /** + * Validates the existence of Referral entities with the given client reference IDs. + * Checks if the provided Referral entities already exist in the database. + * + * @param request The bulk request containing Referral entities. + * @return A map containing Referral entities and their associated error details if any duplicates are found. + */ + @Override + public Map> validate(ReferralBulkRequest request) { + // Map to hold Referral entities and their error details + Map> errorDetailsMap = new HashMap<>(); + + // Get the list of Referral entities from the request + List entities = request.getReferrals(); + + // Extract client reference IDs from Referral entities that do not have existing errors + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) // Filter out entities that already have errors + .map(Referral::getClientReferenceId) // Extract client reference IDs from Referral entities + .collect(Collectors.toList()); // Collect the IDs into a list + + // Create a map for quick lookup of Referral entities by client reference ID + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + + // Create a search object for querying existing Referral entities by client reference IDs + ReferralSearch referralSearch = ReferralSearch.builder() + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search + .build(); + + // Check if the client reference ID list is not empty before querying the database + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing Referral entities with the given client reference IDs + List existingClientReferenceIds = referralRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, add an error to the map for the corresponding Referral entity + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation + Error error = getErrorForUniqueEntity(); + // Populate error details for the individual Referral entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); + }); + } + + // Return the map containing Referral entities and their associated error details + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmIsDeletedValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmIsDeletedValidator.java new file mode 100644 index 00000000000..ca58f6deb30 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmIsDeletedValidator.java @@ -0,0 +1,34 @@ +package org.egov.referralmanagement.validator; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForIsDelete; + +@Component +@Order(2) +@Slf4j +public class RmIsDeletedValidator implements Validator { + + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating isDeleted field"); + HashMap> errorDetailsMap = new HashMap<>(); + List validEntities = request.getReferrals(); + validEntities.stream().filter(Referral::getIsDeleted).forEach(referral -> { + Error error = getErrorForIsDelete(); + populateErrorDetails(referral, error, errorDetailsMap); + }); + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java new file mode 100644 index 00000000000..cbed1346a10 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java @@ -0,0 +1,94 @@ +package org.egov.referralmanagement.validator; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.referralmanagement.ReferralSearch; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.repository.ReferralRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; +import static org.egov.referralmanagement.Constants.GET_ID; + +@Component +@Order(value = 4) +@Slf4j +public class RmNonExistentEntityValidator implements Validator { + + private final ReferralRepository referralRepository; + + private final ObjectMapper objectMapper; + + @Autowired + public RmNonExistentEntityValidator(ReferralRepository referralRepository, ObjectMapper objectMapper) { + this.referralRepository = referralRepository; + this.objectMapper = objectMapper; + } + + + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating for existence of entity"); + Map> errorDetailsMap = new HashMap<>(); + List referrals = request.getReferrals(); + Class objClass = getObjClass(referrals); + Method idMethod = getMethod(GET_ID, objClass); + Map iMap = getIdToObjMap(referrals + .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + // Lists to store IDs and client reference IDs + List idList = new ArrayList<>(); + List clientReferenceIdList = new ArrayList<>(); + // Extract IDs and client reference IDs from referral entities + referrals.forEach(referral -> { + idList.add(referral.getId()); + clientReferenceIdList.add(referral.getClientReferenceId()); + }); + if (!iMap.isEmpty()) { + + // Create a search object for querying existing entities + ReferralSearch referralSearch = ReferralSearch.builder() + .clientReferenceId(clientReferenceIdList) + .id(idList) + .build(); + + List existingReferrals; + try { + // Query the repository to find existing entities + existingReferrals = referralRepository.find(referralSearch, referrals.size(), 0, + referrals.get(0).getTenantId(), null, false).getResponse(); + } catch (Exception e) { + // Handle query builder exception + log.error("Search failed for Referral with error: {}", e.getMessage(), e); + throw new CustomException("REFERRAL_SEARCH_FAILED", "Search Failed for Referral, " + e.getMessage()); + } + List nonExistentReferrals = checkNonExistentEntities(iMap, + existingReferrals, idMethod); + nonExistentReferrals.forEach(sideEffect -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(sideEffect, error, errorDetailsMap); + }); + } + + return errorDetailsMap; + } +} + diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNullIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNullIdValidator.java new file mode 100644 index 00000000000..07df0399a64 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNullIdValidator.java @@ -0,0 +1,27 @@ +package org.egov.referralmanagement.validator; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +import static org.egov.referralmanagement.Constants.GET_REFERRALS; +import static org.egov.common.utils.CommonUtils.validateForNullId; + + +@Component +@Order(value = 1) +@Slf4j +public class RmNullIdValidator implements Validator { + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating for null id"); + return validateForNullId(request, GET_REFERRALS); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectBeneficiaryIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectBeneficiaryIdValidator.java new file mode 100644 index 00000000000..2029562e8eb --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectBeneficiaryIdValidator.java @@ -0,0 +1,110 @@ +package org.egov.referralmanagement.validator; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.project.BeneficiaryBulkResponse; +import org.egov.common.models.project.BeneficiarySearchRequest; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.models.project.ProjectBeneficiarySearch; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + + +/** + * Validate whether project beneficiary exist in db or not using project beneficiary id and project beneficiary client beneficiary id for Referral object + */ +@Component +@Order(value = 3) +@Slf4j +public class RmProjectBeneficiaryIdValidator implements Validator { + private final ServiceRequestClient serviceRequestClient; + private final ReferralManagementConfiguration referralManagementConfiguration; + + public RmProjectBeneficiaryIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.referralManagementConfiguration = referralManagementConfiguration; + } + + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating project beneficiary id"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getReferrals(); + Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(Referral::getTenantId)); + tenantIdReferralMap.forEach((tenantId, referralList) -> { + /** Get all the existing project beneficiaries in the referral list from Project Service + */ + List existingProjectBeneficiaries = getExistingProjectBeneficiaries(tenantId, referralList, request); + /** Validate project beneficiaries and populate error map if invalid entities are found + */ + validateAndPopulateErrors(existingProjectBeneficiaries, entities, errorDetailsMap); + }); + return errorDetailsMap; + } + private void addIgnoreNull(List list, String item) { + if(Objects.nonNull(item)) list.add(item); + } + + private List getExistingProjectBeneficiaries(String tenantId, List referrals, ReferralBulkRequest request) { + List existingProjectBeneficiaries = null; + final List projectBeneficiaryIdList = new ArrayList<>(); + final List projectBeneficiaryClientReferenceIdList = new ArrayList<>(); + referrals.forEach(referral -> { + addIgnoreNull(projectBeneficiaryIdList, referral.getProjectBeneficiaryId()); + addIgnoreNull(projectBeneficiaryClientReferenceIdList, referral.getProjectBeneficiaryClientReferenceId()); + }); + ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() + .id(projectBeneficiaryIdList.isEmpty() ? null : projectBeneficiaryIdList) + .clientReferenceId(projectBeneficiaryClientReferenceIdList.isEmpty() ? null : projectBeneficiaryClientReferenceIdList) + .build(); + try { + // using project beneficiary search and fetching the valid ids. + BeneficiaryBulkResponse beneficiaryBulkResponse = serviceRequestClient.fetchResult( + new StringBuilder(referralManagementConfiguration.getProjectHost() + + referralManagementConfiguration.getProjectBeneficiarySearchUrl() + +"?limit=" + referrals.size() + + "&offset=0&tenantId=" + tenantId), + BeneficiarySearchRequest.builder().requestInfo(request.getRequestInfo()).projectBeneficiary(projectBeneficiarySearch).build(), + BeneficiaryBulkResponse.class + ); + existingProjectBeneficiaries = beneficiaryBulkResponse.getProjectBeneficiaries(); + } catch (Exception e) { + throw new CustomException("Project Beneficiaries failed to fetch", "Exception : "+e.getMessage()); + } + return existingProjectBeneficiaries; + } + + private void validateAndPopulateErrors(List existingProjectBeneficiaries, List entities, Map> errorDetailsMap) { + final List existingProjectBeneficiaryIds = new ArrayList<>(); + final List existingProjectBeneficiaryClientReferenceIds = new ArrayList<>(); + existingProjectBeneficiaries.forEach(projectBeneficiary -> { + existingProjectBeneficiaryIds.add(projectBeneficiary.getId()); + existingProjectBeneficiaryClientReferenceIds.add(projectBeneficiary.getClientReferenceId()); + }); + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + (Objects.nonNull(entity.getProjectBeneficiaryClientReferenceId()) && !existingProjectBeneficiaryClientReferenceIds.contains(entity.getProjectBeneficiaryClientReferenceId()) ) + || (Objects.nonNull(entity.getProjectBeneficiaryId()) && !existingProjectBeneficiaryIds.contains(entity.getProjectBeneficiaryId())) + ).collect(Collectors.toList()); + invalidEntities.forEach(referral -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(referral, error, errorDetailsMap); + }); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmRecipientIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmRecipientIdValidator.java new file mode 100644 index 00000000000..a068a4882f2 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmRecipientIdValidator.java @@ -0,0 +1,107 @@ +package org.egov.referralmanagement.validator; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.ds.Tuple; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.service.UserService; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.service.FacilityService; +import org.egov.referralmanagement.util.ValidatorUtil; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; +import static org.egov.referralmanagement.Constants.FACILITY; +import static org.egov.referralmanagement.Constants.INVALID_RECIPIENT_TYPE; +import static org.egov.referralmanagement.Constants.STAFF; + +/** + * + */ +@Component +@Order(value = 3) +@Slf4j +public class RmRecipientIdValidator implements Validator { + private final FacilityService facilityService; + private final UserService userService; + + public RmRecipientIdValidator(FacilityService facilityService, UserService userService) { + this.facilityService = facilityService; + this.userService = userService; + } + + /** + * @param request + * @return + */ + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating recipient id"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getReferrals(); + Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(Referral::getTenantId)); + tenantIdReferralMap.forEach((tenantId, referralList) -> { + + Tuple, List> tuple = getInvalidStaffAndFacilityId(request, entities, tenantId, referralList, errorDetailsMap); + // validate and populate error if found. + validateAndPopulateErrors(entities, tuple.getX(), tuple.getY(), errorDetailsMap); + }); + return errorDetailsMap; + } + + private void addIgnoreNull(List list, String item) { + if(Objects.nonNull(item)) list.add(item); + } + + private Tuple, List> getInvalidStaffAndFacilityId(ReferralBulkRequest request, List entities, String tenantId, List referralList, Map> errorDetailsMap) { + final List projectStaffUuidList = new ArrayList<>(); + final List facilityIdList = new ArrayList<>(); + referralList.forEach(referral -> { + switch (referral.getRecipientType()) { + case STAFF : + addIgnoreNull(projectStaffUuidList, referral.getRecipientId()); + break; + case FACILITY: + addIgnoreNull(facilityIdList, referral.getRecipientId()); + break; + default: + throw new CustomException(INVALID_RECIPIENT_TYPE, "Exception : The Recipient Type is invalid."); + } + }); + + List invalidStaffIds = new ArrayList<>(projectStaffUuidList); + // fetch valid identifiers and remove it from invalidStaffIds + ValidatorUtil.validateAndEnrichStaffIds(request.getRequestInfo(), userService, projectStaffUuidList, invalidStaffIds); + + // fetch valid facilities and remove it from invalidfacilityIds + List invalidFacilityIds = new ArrayList<>(facilityIdList); + List validFacilityIds = facilityService.validateFacilityIds(facilityIdList, entities, tenantId, + errorDetailsMap, request.getRequestInfo()); + invalidFacilityIds.removeAll(validFacilityIds); + + return new Tuple<>(invalidStaffIds, invalidFacilityIds); + } + + private void validateAndPopulateErrors(List entities, List invalidStaffIds, List invalidFacilityIds, Map> errorDetailsMap) { + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + entity.getRecipientType().equals(STAFF) ? invalidStaffIds.contains(entity.getRecipientId()) : invalidFacilityIds.contains(entity.getRecipientId()) + ).collect(Collectors.toList()); + + invalidEntities.forEach(referral -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(referral, error, errorDetailsMap); + }); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmReferrerIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmReferrerIdValidator.java new file mode 100644 index 00000000000..10f5e265579 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmReferrerIdValidator.java @@ -0,0 +1,86 @@ +package org.egov.referralmanagement.validator; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.service.UserService; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.service.FacilityService; +import org.egov.referralmanagement.util.ValidatorUtil; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + +/** + * Validate the referrer using user service + */ +@Component +@Order(value = 3) +@Slf4j +public class RmReferrerIdValidator implements Validator { + + private final FacilityService facilityService; + private final UserService userService; + + public RmReferrerIdValidator(FacilityService facilityService, UserService userService) { + this.facilityService = facilityService; + this.userService = userService; + } + + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating referrer id"); + + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getReferrals(); + + Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(Referral::getTenantId)); + + tenantIdReferralMap.forEach((tenantId, referralList) -> { + List invalidStaffIds = getInvalidStaffIds(referralList, request); + validateAndPopulateError(entities, invalidStaffIds, errorDetailsMap); + }); + + return errorDetailsMap; + } + private void addIgnoreNull(List list, String item) { + if(Objects.nonNull(item)) list.add(item); + } + + private List getInvalidStaffIds(List referralList, ReferralBulkRequest request) { + final List projectStaffUuidList = new ArrayList<>(); + referralList.forEach(referral -> addIgnoreNull(projectStaffUuidList, referral.getReferrerId())); + + List invalidStaffIds = new ArrayList<>(projectStaffUuidList); + try { + ValidatorUtil.validateAndEnrichStaffIds(request.getRequestInfo(), userService, projectStaffUuidList, invalidStaffIds); + } catch (Exception e) { + throw new CustomException("Project Staff failed to fetch", "Exception : "+e.getMessage()); + } + + return invalidStaffIds; + } + private void validateAndPopulateError(List entities, List invalidStaffIds, Map> errorDetailsMap) { + + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + invalidStaffIds.contains(entity.getReferrerId()) + ).collect(Collectors.toList()); + + invalidEntities.forEach(referral -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(referral, error, errorDetailsMap); + }); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmRowVersionValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmRowVersionValidator.java new file mode 100644 index 00000000000..7c45f467c6d --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmRowVersionValidator.java @@ -0,0 +1,83 @@ +package org.egov.referralmanagement.validator; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.repository.ReferralRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.getEntitiesWithMismatchedRowVersion; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForRowVersionMismatch; + +/* +* +* Validator for checking row version consistency of Referral entities in a bulk request. +* It retrieves existing Referral entities from the repository, compares row versions, +* and populates error details for entities with mismatched row versions. +* +* @author syed-egov +* */ + +@Component +@Order(value = 5) +@Slf4j +public class RmRowVersionValidator implements Validator { + + private ReferralRepository referralRepository; + + @Autowired + public RmRowVersionValidator(ReferralRepository referralRepository) { + this.referralRepository = referralRepository; + } + + /* + * + * @param referralBulkRequest The bulk request containing Referral entities to be validated. + * @return A map containing Referral entities with associated error details + * for entities with mismatched row versions. + */ + + @Override + public Map> validate(ReferralBulkRequest referralBulkRequest) { + log.info("validating row version"); + // Map to store Referral entities with associated error details + Map> errorDetailsMap = new HashMap<>(); + // Get the method used for obtaining entity IDs + Method idMethod = getIdMethod(referralBulkRequest.getReferrals()); + // Create a map of entity IDs to Referral entities for entities without errors + Map iMap = getIdToObjMap(referralBulkRequest.getReferrals() + .stream() + .filter(notHavingErrors()) + .collect(Collectors.toList()),idMethod); + // Check if the map of IDs to Referral entities is not empty + if(!iMap.isEmpty()){ + List referralIds = new ArrayList<>(iMap.keySet()); + // Retrieve existing Referral entities from the repository + List existingReferrals = referralRepository.findById(referralIds,false,getIdFieldName(idMethod)); + // Identify entities with mismatched row versions + List entitiesWithMismatchedVersion = getEntitiesWithMismatchedRowVersion(iMap,existingReferrals,idMethod); + // Populate error details for entities with mismatched row versions + entitiesWithMismatchedVersion.forEach(referral -> { + Error error = getErrorForRowVersionMismatch(); + populateErrorDetails(referral, error, errorDetailsMap); + }); + } + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmSideEffectIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmSideEffectIdValidator.java new file mode 100644 index 00000000000..cd3d8c57ac1 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmSideEffectIdValidator.java @@ -0,0 +1,89 @@ +package org.egov.referralmanagement.validator; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.service.SideEffectService; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + +/** + * Validate Side Effect id from the Referral Objects + */ +@Component +@Order(value = 3) +@Slf4j +public class RmSideEffectIdValidator implements Validator { + private final SideEffectService sideEffectService; + public RmSideEffectIdValidator(SideEffectService sideEffectService) { + this.sideEffectService = sideEffectService; + } + + /** + * @param request + * @return + */ + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating project beneficiary id"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getReferrals(); + Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(Referral::getTenantId)); + tenantIdReferralMap.forEach((tenantId, referralList) -> { + List sideEffectIds = new ArrayList<>(); + referralList.forEach(referral -> { + if (Objects.nonNull(referral.getSideEffect())) + addIgnoreNull(sideEffectIds, referral.getSideEffect().getId()); + }); + List validSideEffectIds = new ArrayList<>(); + if(!sideEffectIds.isEmpty()) { + try { + validSideEffectIds = sideEffectService.search( + SideEffectSearchRequest.builder().sideEffect(SideEffectSearch.builder().id(sideEffectIds).build()).build(), + sideEffectIds.size(), 0, tenantId, null, false + ).getResponse().stream().map(SideEffect::getId).collect(Collectors.toList()); + } catch (Exception e) { + throw new CustomException("Side Effect failed to fetch", "Exception : " + e.getMessage()); + } + } + sideEffectIds.removeAll(validSideEffectIds); + List invalidSideEffectIds = new ArrayList<>(sideEffectIds); + + validateAndPopulateErrors(entities, invalidSideEffectIds, errorDetailsMap); + + }); + + return errorDetailsMap; + } + private void addIgnoreNull(List list, String item) { + if(Objects.nonNull(item)) list.add(item); + } + + private void validateAndPopulateErrors(List entities, List invalidSideEffectIds, Map> errorDetailsMap) { + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + Objects.nonNull(entity.getSideEffect()) && invalidSideEffectIds.contains(entity.getSideEffect().getId()) + ).collect(Collectors.toList()); + + invalidEntities.forEach(referral -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(referral, error, errorDetailsMap); + }); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmUniqueEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmUniqueEntityValidator.java new file mode 100644 index 00000000000..e35159b57f7 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmUniqueEntityValidator.java @@ -0,0 +1,47 @@ +package org.egov.referralmanagement.validator; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +@Component +@Order(value = 2) +@Slf4j +public class RmUniqueEntityValidator implements Validator { + + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating unique entity"); + Map> errorDetailsMap = new HashMap<>(); + List validEntities = request.getReferrals() + .stream().filter(notHavingErrors()).collect(Collectors.toList()); + if (!validEntities.isEmpty()) { + Map eMap = getIdToObjMap(validEntities); + if (eMap.keySet().size() != validEntities.size()) { + List duplicates = eMap.keySet().stream().filter(id -> + validEntities.stream() + .filter(entity -> entity.getId().equals(id)).count() > 1 + ).collect(Collectors.toList()); + for (String key : duplicates) { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(eMap.get(key), error, errorDetailsMap); + } + } + } + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrExistentEntityValidator.java new file mode 100644 index 00000000000..de041f238e8 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrExistentEntityValidator.java @@ -0,0 +1,94 @@ +package org.egov.referralmanagement.validator.hfreferral; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralSearch; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.repository.HFReferralRepository; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of HFReferral entities with the given client reference IDs. + * This validator checks if the provided HFReferral entities already exist in the database based on their client reference IDs. + * + * @author kanishq-egov + */ +@Component +@Order(value = 1) +@Slf4j +public class HfrExistentEntityValidator implements Validator { + + private final HFReferralRepository hfReferralRepository; + + /** + * Constructor to initialize the HFReferralRepository dependency. + * + * @param hfReferralRepository The repository for HFReferral entities. + */ + public HfrExistentEntityValidator(HFReferralRepository hfReferralRepository) { + this.hfReferralRepository = hfReferralRepository; + } + + /** + * Validates the existence of HFReferral entities in the HFReferralBulkRequest. + * Checks if the provided HFReferral entities already exist in the database based on their client reference IDs. + * + * @param request The bulk request containing HFReferral entities. + * @return A map containing HFReferral entities and their associated error details if any duplicates are found. + */ + @Override + public Map> validate(HFReferralBulkRequest request) { + // Map to hold HFReferral entities and their error details. + Map> errorDetailsMap = new HashMap<>(); + + // Get the list of HFReferral entities from the request. + List entities = request.getHfReferrals(); + + // Extract client reference IDs from HFReferral entities that do not have existing errors. + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) // Filter out entities that already have errors. + .map(HFReferral::getClientReferenceId) // Extract client reference IDs from HFReferral entities. + .collect(Collectors.toList()); // Collect the IDs into a list. + + // Create a map for quick lookup of HFReferral entities by client reference ID. + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty. + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map. + + // Create a search object for querying existing HFReferral entities by client reference IDs. + HFReferralSearch hfReferralSearch = HFReferralSearch.builder() + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search. + .build(); + + // Check if the client reference ID list is not empty before querying the database. + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing HFReferral entities with the given client reference IDs. + List existingClientReferenceIds = hfReferralRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, add an error to the map for the corresponding HFReferral entity. + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation. + Error error = getErrorForUniqueEntity(); + // Populate error details for the individual HFReferral entity associated with the client reference ID. + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); + }); + } + + // Return the map containing HFReferral entities and their associated error details. + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrIsDeletedValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrIsDeletedValidator.java new file mode 100644 index 00000000000..92a2fcfdd53 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrIsDeletedValidator.java @@ -0,0 +1,45 @@ +package org.egov.referralmanagement.validator.hfreferral; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForIsDelete; + +/** + * Validator for checking the 'isDeleted' field in HFReferral entities. + * + * Author: kanishq-egov + */ +@Component +@Order(2) +@Slf4j +public class HfrIsDeletedValidator implements Validator { + + /** + * Validates the 'isDeleted' field for each HFReferral entity in the bulk request. + * + * @param request The HFReferralBulkRequest containing a list of HFReferral entities + * @return A Map containing HFReferral entities as keys and lists of errors as values + */ + @Override + public Map> validate(HFReferralBulkRequest request) { + log.info("validating isDeleted field"); + HashMap> errorDetailsMap = new HashMap<>(); + List validEntities = request.getHfReferrals(); + validEntities.stream().filter(HFReferral::getIsDeleted).forEach(hfReferral -> { + Error error = getErrorForIsDelete(); + populateErrorDetails(hfReferral, error, errorDetailsMap); + }); + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNonExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNonExistentEntityValidator.java new file mode 100644 index 00000000000..3011cef48ce --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNonExistentEntityValidator.java @@ -0,0 +1,101 @@ +package org.egov.referralmanagement.validator.hfreferral; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralSearch; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.repository.HFReferralRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; +import static org.egov.referralmanagement.Constants.GET_ID; + +/** + * Validator for checking the existence of entities referred in HFReferral entities. + * + * Author: kanishq-egov + */ +@Component +@Order(value = 4) +@Slf4j +public class HfrNonExistentEntityValidator implements Validator { + + private final HFReferralRepository hfReferralRepository; + + private final ObjectMapper objectMapper; + + @Autowired + public HfrNonExistentEntityValidator(HFReferralRepository hfReferralRepository, ObjectMapper objectMapper) { + this.hfReferralRepository = hfReferralRepository; + this.objectMapper = objectMapper; + } + + /** + * Validates the existence of entities referred in HFReferral entities. + * + * @param request The HFReferralBulkRequest containing a list of HFReferral entities + * @return A Map containing HFReferral entities as keys and lists of errors as values + */ + @Override + public Map> validate(HFReferralBulkRequest request) { + log.info("validating for existence of entity"); + Map> errorDetailsMap = new HashMap<>(); + List hfReferrals = request.getHfReferrals(); + Class objClass = getObjClass(hfReferrals); + Method idMethod = getMethod(GET_ID, objClass); + Map iMap = getIdToObjMap(hfReferrals + .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + // Lists to store IDs and client reference IDs + List idList = new ArrayList<>(); + List clientReferenceIdList = new ArrayList<>(); + // Extract IDs and client reference IDs from HfReferral entities + hfReferrals.forEach(entity -> { + idList.add(entity.getId()); + clientReferenceIdList.add(entity.getClientReferenceId()); + }); + if (!iMap.isEmpty()) { + HFReferralSearch hfReferralSearch = HFReferralSearch.builder() + .clientReferenceId(clientReferenceIdList) + .id(idList) + .build(); + + List existingReferrals; + try { + // Query the repository to find existing entities + existingReferrals = hfReferralRepository.find(hfReferralSearch, hfReferrals.size(), 0, + hfReferrals.get(0).getTenantId(), null, false); + } catch (Exception e) { + // Handle query builder exception + log.error("Search failed for HFReferral with error: {}", e.getMessage(), e); + throw new CustomException("HFREFERRAL_SEARCH_FAILED", "Search Failed for HFReferral, " + e.getMessage()); + } + List nonExistentReferrals = checkNonExistentEntities(iMap, + existingReferrals, idMethod); + nonExistentReferrals.forEach(sideEffect -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(sideEffect, error, errorDetailsMap); + }); + } + + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNullIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNullIdValidator.java new file mode 100644 index 00000000000..26defef4fa4 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNullIdValidator.java @@ -0,0 +1,38 @@ +package org.egov.referralmanagement.validator.hfreferral; + +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.validateForNullId; +import static org.egov.referralmanagement.Constants.GET_HF_REFERRALS; + +/** + * Validator for checking null id in HFReferral entities. + * + * Author: kanishq-egov + */ +@Component +@Order(value = 1) +@Slf4j +public class HfrNullIdValidator implements Validator { + + /** + * Validates if HFReferral entities have null ids. + * + * @param request The HFReferralBulkRequest containing a list of HFReferral entities + * @return A Map containing HFReferral entities as keys and lists of errors as values + */ + @Override + public Map> validate(HFReferralBulkRequest request) { + log.info("validating for null id"); + return validateForNullId(request, GET_HF_REFERRALS); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectFacilityIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectFacilityIdValidator.java new file mode 100644 index 00000000000..2cadd5e38ab --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectFacilityIdValidator.java @@ -0,0 +1,133 @@ +package org.egov.referralmanagement.validator.hfreferral; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.project.ProjectFacility; +import org.egov.common.models.project.ProjectFacilityBulkResponse; +import org.egov.common.models.project.ProjectFacilitySearch; +import org.egov.common.models.project.ProjectFacilitySearchRequest; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + +/** + * Validator for checking the existence of ProjectFacility entities based on their IDs in HFReferral objects. + * + * Author: kanishq-egov + */ +@Component +@Order(value = 3) +@Slf4j +public class HfrProjectFacilityIdValidator implements Validator { + + private final ServiceRequestClient serviceRequestClient; + private final ReferralManagementConfiguration referralManagementConfiguration; + + public HfrProjectFacilityIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.referralManagementConfiguration = referralManagementConfiguration; + } + + /** + * Validates whether project facilities exist in the database or not using project facility IDs for HFReferral objects. + * + * @param request The HFReferralBulkRequest containing a list of HFReferral entities + * @return A Map containing HFReferral entities as keys and lists of errors as values + */ + @Override + public Map> validate(HFReferralBulkRequest request) { + log.info("Validating project facility IDs"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getHfReferrals(); + + // Grouping HFReferrals by tenantId to fetch project facilities for each tenant + Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(HFReferral::getTenantId)); + tenantIdReferralMap.forEach((tenantId, hfReferralList) -> { + // Get all the existing project facilities in the HFReferral list from Project Service + List existingProjectFacilities = getExistingProjects(tenantId, hfReferralList, request); + // Validate project facilities and populate error map if invalid entities are found + validateAndPopulateErrors(existingProjectFacilities, entities, errorDetailsMap); + }); + + return errorDetailsMap; + } + + // Helper method to add an item to a list if it is not null + private void addIgnoreNull(List list, String item) { + if(Objects.nonNull(item)) list.add(item); + } + + // Fetches existing project facilities from Project Service based on their IDs + private List getExistingProjects(String tenantId, List hfReferrals, HFReferralBulkRequest request) { + List existingProjectFacilities = new ArrayList<>(); + final List projectFacilityIdList = new ArrayList<>(); + + // Collecting project facility IDs from HFReferrals + hfReferrals.forEach(hfReferral -> { + addIgnoreNull(projectFacilityIdList, hfReferral.getProjectFacilityId()); + }); + + if(!projectFacilityIdList.isEmpty()) { + ProjectFacilitySearch projectFacilitySearch = ProjectFacilitySearch.builder() + .id(!projectFacilityIdList.isEmpty()? projectFacilityIdList : null) + .build(); + + try { + // Using project facility search and fetching the valid IDs. + ProjectFacilityBulkResponse projectFacilityBulkResponse = serviceRequestClient.fetchResult( + new StringBuilder(referralManagementConfiguration.getProjectHost() + + referralManagementConfiguration.getProjectFacilitySearchUrl() + +"?limit=" + hfReferrals.size() + + "&offset=0&tenantId=" + tenantId), + ProjectFacilitySearchRequest.builder() + .requestInfo(request.getRequestInfo()) + .projectFacility(projectFacilitySearch) + .build(), + ProjectFacilityBulkResponse.class + ); + existingProjectFacilities = projectFacilityBulkResponse.getProjectFacilities(); + } catch (Exception e) { + throw new CustomException("Project Facilities failed to fetch", "Exception : "+e.getMessage()); + } + } + + return existingProjectFacilities; + } + + // Validates project facilities and populates the error map if invalid entities are found + private void validateAndPopulateErrors(List existingProjectFacilities, List entities, Map> errorDetailsMap) { + final List existingProjectFacilityIds = new ArrayList<>(); + + // Extracting IDs from existing project facilities + existingProjectFacilities.forEach(projectFacility -> { + existingProjectFacilityIds.add(projectFacility.getId()); + }); + + // Filtering invalid entities + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + Objects.nonNull(entity.getProjectFacilityId()) && !existingProjectFacilityIds.contains(entity.getProjectFacilityId()) + ).collect(Collectors.toList()); + + // Populating error details for invalid entities + invalidEntities.forEach(hfReferral -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(hfReferral, error, errorDetailsMap); + }); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectIdValidator.java new file mode 100644 index 00000000000..78fc23289c4 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectIdValidator.java @@ -0,0 +1,131 @@ +package org.egov.referralmanagement.validator.hfreferral; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.project.Project; +import org.egov.common.models.project.ProjectRequest; +import org.egov.common.models.project.ProjectResponse; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + +/** + * Validator for checking the existence of Project entities based on their IDs in HFReferral objects. + * + * Author: kanishq-egov + */ +@Component +@Order(value = 3) +@Slf4j +public class HfrProjectIdValidator implements Validator { + + private final ServiceRequestClient serviceRequestClient; + private final ReferralManagementConfiguration referralManagementConfiguration; + + public HfrProjectIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.referralManagementConfiguration = referralManagementConfiguration; + } + + /** + * Validates whether projects exist in the database or not using project IDs for HFReferral objects. + * + * @param request The HFReferralBulkRequest containing a list of HFReferral entities + * @return A Map containing HFReferral entities as keys and lists of errors as values + */ + @Override + public Map> validate(HFReferralBulkRequest request) { + log.info("Validating project IDs"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getHfReferrals(); + + // Grouping HFReferrals by tenantId to fetch projects for each tenant + Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(HFReferral::getTenantId)); + tenantIdReferralMap.forEach((tenantId, hfReferralList) -> { + // Get all the existing projects in the hfReferral list from Project Service + List existingProjects = getExistingProjects(tenantId, hfReferralList, request); + // Validate projects and populate error map if invalid entities are found + validateAndPopulateErrors(existingProjects, entities, errorDetailsMap); + }); + + return errorDetailsMap; + } + + // Helper method to add an item to a list if it is not null + private void addIgnoreNull(List list, String item) { + if (Objects.nonNull(item)) list.add(item); + } + + // Fetches existing projects from Project Service based on their IDs + private List getExistingProjects(String tenantId, List hfReferrals, HFReferralBulkRequest request) { + List existingProjects = null; + final List projectIdList = new ArrayList<>(); + + // Collecting project IDs from HFReferrals + hfReferrals.forEach(hfReferral -> { + addIgnoreNull(projectIdList, hfReferral.getProjectId()); + }); + + if (!projectIdList.isEmpty()) { + List projects = new ArrayList<>(); + projectIdList.forEach(projectId -> projects.add(Project.builder().id(projectId).tenantId(tenantId).build())); + + try { + // Using project search and fetching the valid IDs. + ProjectResponse projectResponse = serviceRequestClient.fetchResult( + new StringBuilder(referralManagementConfiguration.getProjectHost() + + referralManagementConfiguration.getProjectSearchUrl() + + "?limit=" + hfReferrals.size() + + "&offset=0&tenantId=" + tenantId), + ProjectRequest.builder() + .requestInfo(request.getRequestInfo()) + .projects(projects) + .build(), + ProjectResponse.class + ); + existingProjects = projectResponse.getProject(); + } catch (Exception e) { + throw new CustomException("Projects failed to fetch", "Exception : " + e.getMessage()); + } + } + + return existingProjects; + } + + // Validates projects and populates the error map if invalid entities are found + private void validateAndPopulateErrors(List existingProjects, List entities, Map> errorDetailsMap) { + final List existingProjectIds = new ArrayList<>(); + + // Extracting IDs from existing projects + existingProjects.forEach(project -> { + existingProjectIds.add(project.getId()); + }); + + // Filtering invalid entities + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + Objects.nonNull(entity.getProjectId()) && !existingProjectIds.contains(entity.getProjectId()) + ).collect(Collectors.toList()); + + // Populating error details for invalid entities + invalidEntities.forEach(hfReferral -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(hfReferral, error, errorDetailsMap); + }); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrRowVersionValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrRowVersionValidator.java new file mode 100644 index 00000000000..e5d62bfee0a --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrRowVersionValidator.java @@ -0,0 +1,74 @@ +package org.egov.referralmanagement.validator.hfreferral; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.repository.HFReferralRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.getEntitiesWithMismatchedRowVersion; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForRowVersionMismatch; + +/** + * + * Validator for checking row version mismatch in HFReferral entities during bulk processing. + * Ensures that the row version of existing entities matches the row version in the request. + * + * @author kanishq-egov + */ +@Component +@Order(value = 5) +@Slf4j +public class HfrRowVersionValidator implements Validator { + + private final HFReferralRepository hfReferralRepository; + + @Autowired + public HfrRowVersionValidator(HFReferralRepository hfReferralRepository) { + this.hfReferralRepository = hfReferralRepository; + } + + /** + * Validates row version for HFReferral entities in a bulk request. + * + * @param request The HFReferralBulkRequest containing a list of HFReferral entities + * @return A Map containing HFReferral entities as keys and lists of errors as values + */ + @Override + public Map> validate(HFReferralBulkRequest request) { + log.info("Validating row version"); + Map> errorDetailsMap = new HashMap<>(); + Method idMethod = getIdMethod(request.getHfReferrals()); + Map iMap = getIdToObjMap(request.getHfReferrals().stream() + .filter(notHavingErrors()) + .collect(Collectors.toList()), idMethod); + if (!iMap.isEmpty()) { + List hfReferralIds = new ArrayList<>(iMap.keySet()); + List existingHfReferrals = hfReferralRepository.findById(hfReferralIds, + false, getIdFieldName(idMethod)); + List entitiesWithMismatchedRowVersion = + getEntitiesWithMismatchedRowVersion(iMap, existingHfReferrals, idMethod); + entitiesWithMismatchedRowVersion.forEach(hfReferral -> { + Error error = getErrorForRowVersionMismatch(); + populateErrorDetails(hfReferral, error, errorDetailsMap); + }); + } + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrUniqueEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrUniqueEntityValidator.java new file mode 100644 index 00000000000..42c84640201 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrUniqueEntityValidator.java @@ -0,0 +1,65 @@ +package org.egov.referralmanagement.validator.hfreferral; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * + * Validator for checking uniqueness of HFReferral entities in a bulk request. + * Ensures that there are no duplicate entities based on their IDs. + * + * Author: kanishq-egov + */ +@Component +@Order(value = 2) +@Slf4j +public class HfrUniqueEntityValidator implements Validator { + + /** + * Validates the uniqueness of HFReferral entities based on their IDs. + * + * @param request The HFReferralBulkRequest containing a list of HFReferral entities + * @return A Map containing HFReferral entities as keys and lists of errors as values + */ + @Override + public Map> validate(HFReferralBulkRequest request) { + log.info("Validating unique entity"); + Map> errorDetailsMap = new HashMap<>(); + List validEntities = request.getHfReferrals() + .stream().filter(notHavingErrors()).collect(Collectors.toList()); + if (!validEntities.isEmpty()) { + // Create a map of entity IDs to HFReferral objects + Map eMap = getIdToObjMap(validEntities); + + // Check for duplicate IDs + if (eMap.keySet().size() != validEntities.size()) { + List duplicates = eMap.keySet().stream().filter(id -> + validEntities.stream() + .filter(entity -> entity.getId().equals(id)).count() > 1 + ).collect(Collectors.toList()); + + // Populate errors for duplicate entities + for (String key : duplicates) { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(eMap.get(key), error, errorDetailsMap); + } + } + } + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeExistentEntityValidator.java new file mode 100644 index 00000000000..961272cb95d --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeExistentEntityValidator.java @@ -0,0 +1,94 @@ +package org.egov.referralmanagement.validator.sideeffect; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.repository.SideEffectRepository; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of SideEffect entities with the given client reference IDs. + * This validator checks if the provided SideEffect entities already exist in the database based on their client reference IDs. + * + * @author kanishq-egov + */ +@Component +@Order(value = 1) +@Slf4j +public class SeExistentEntityValidator implements Validator { + + private final SideEffectRepository sideEffectRepository; + + /** + * Constructor to initialize the SideEffectRepository dependency. + * + * @param sideEffectRepository The repository for SideEffect entities. + */ + public SeExistentEntityValidator(SideEffectRepository sideEffectRepository) { + this.sideEffectRepository = sideEffectRepository; + } + + /** + * Validates the existence of SideEffect entities in the SideEffectBulkRequest. + * Checks if the provided SideEffect entities already exist in the database based on their client reference IDs. + * + * @param request The bulk request containing SideEffect entities. + * @return A map containing SideEffect entities and their associated error details if any duplicates are found. + */ + @Override + public Map> validate(SideEffectBulkRequest request) { + // Map to hold SideEffect entities and their error details + Map> errorDetailsMap = new HashMap<>(); + + // Get the list of SideEffect entities from the request + List entities = request.getSideEffects(); + + // Extract client reference IDs from SideEffect entities that do not have existing errors + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) // Filter out entities that already have errors + .map(SideEffect::getClientReferenceId) // Extract client reference IDs from SideEffect entities + .collect(Collectors.toList()); // Collect the IDs into a list + + // Create a map for quick lookup of SideEffect entities by client reference ID + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + + // Create a search object for querying existing SideEffect entities by client reference IDs + SideEffectSearch sideEffectSearch = SideEffectSearch.builder() + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search + .build(); + + // Check if the client reference ID list is not empty before querying the database + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing SideEffect entities with the given client reference IDs + List existingClientReferenceIds = sideEffectRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, add an error to the map for the corresponding SideEffect entity + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation + Error error = getErrorForUniqueEntity(); + // Populate error details for the individual SideEffect entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); + }); + } + + // Return the map containing SideEffect entities and their associated error details + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java new file mode 100644 index 00000000000..b6e4d3f94f3 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java @@ -0,0 +1,34 @@ +package org.egov.referralmanagement.validator.sideeffect; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForIsDelete; + +@Component +@Order(2) +@Slf4j +public class SeIsDeletedValidator implements Validator { + + @Override + public Map> validate(SideEffectBulkRequest request) { + log.info("validating isDeleted field"); + HashMap> errorDetailsMap = new HashMap<>(); + List validIndividuals = request.getSideEffects(); + validIndividuals.stream().filter(SideEffect::getIsDeleted).forEach(individual -> { + Error error = getErrorForIsDelete(); + populateErrorDetails(individual, error, errorDetailsMap); + }); + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java new file mode 100644 index 00000000000..adbc83e68c4 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java @@ -0,0 +1,93 @@ +package org.egov.referralmanagement.validator.sideeffect; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.repository.SideEffectRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; +import static org.egov.referralmanagement.Constants.GET_ID; + +@Component +@Order(value = 4) +@Slf4j +public class SeNonExistentEntityValidator implements Validator { + + private final SideEffectRepository sideEffectRepository; + + private final ObjectMapper objectMapper; + + @Autowired + public SeNonExistentEntityValidator(SideEffectRepository sideEffectRepository, ObjectMapper objectMapper) { + this.sideEffectRepository = sideEffectRepository; + this.objectMapper = objectMapper; + } + + + @Override + public Map> validate(SideEffectBulkRequest request) { + log.info("validating for existence of entity"); + Map> errorDetailsMap = new HashMap<>(); + List sideEffects = request.getSideEffects(); + Class objClass = getObjClass(sideEffects); + Method idMethod = getMethod(GET_ID, objClass); + Map iMap = getIdToObjMap(sideEffects + .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + // Lists to store IDs and client reference IDs + List idList = new ArrayList<>(); + List clientReferenceIdList = new ArrayList<>(); + // Extract IDs and client reference IDs from Side Effect entities + sideEffects.forEach(sideEffect -> { + idList.add(sideEffect.getId()); + clientReferenceIdList.add(sideEffect.getClientReferenceId()); + }); + if (!iMap.isEmpty()) { + SideEffectSearch sideEffectSearch = SideEffectSearch.builder() + .clientReferenceId(clientReferenceIdList) + .id(idList) + .build(); + + List existingSideEffects; + try { + // Query the repository to find existing entities + existingSideEffects = sideEffectRepository.find(sideEffectSearch, sideEffects.size(), 0, + sideEffects.get(0).getTenantId(), null, false).getResponse(); + } catch (Exception e) { + // Handle query builder exception + log.error("Search failed for SideEffect with error: {}", e.getMessage(), e); + throw new CustomException("SIDE_EFFECT_SEARCH_FAILED", "Search Failed for SideEffect, " + e.getMessage()); + } + + List nonExistentIndividuals = checkNonExistentEntities(iMap, + existingSideEffects, idMethod); + nonExistentIndividuals.forEach(sideEffect -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(sideEffect, error, errorDetailsMap); + }); + } + + return errorDetailsMap; + } +} + diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNullIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNullIdValidator.java new file mode 100644 index 00000000000..f27f88830c4 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNullIdValidator.java @@ -0,0 +1,27 @@ +package org.egov.referralmanagement.validator.sideeffect; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +import static org.egov.referralmanagement.Constants.GET_SIDE_EFFECTS; +import static org.egov.common.utils.CommonUtils.validateForNullId; + + +@Component +@Order(value = 1) +@Slf4j +public class SeNullIdValidator implements Validator { + @Override + public Map> validate(SideEffectBulkRequest request) { + log.info("validating for null id"); + return validateForNullId(request, GET_SIDE_EFFECTS); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java new file mode 100644 index 00000000000..216d7d48507 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java @@ -0,0 +1,111 @@ +package org.egov.referralmanagement.validator.sideeffect; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.project.BeneficiaryBulkResponse; +import org.egov.common.models.project.BeneficiarySearchRequest; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.models.project.ProjectBeneficiarySearch; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + +/** + * Validate whether project beneficiary exist in db or not using project beneficiary id and project beneficiary client beneficiary id for SideEffect object + */ +@Component +@Order(value = 3) +@Slf4j +public class SeProjectBeneficiaryIdValidator implements Validator { + private final ServiceRequestClient serviceRequestClient; + private final ReferralManagementConfiguration referralManagementConfiguration; + + @Autowired + public SeProjectBeneficiaryIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.referralManagementConfiguration = referralManagementConfiguration; + } + + /** + * + * @param request + * @return + */ + @Override + public Map> validate(SideEffectBulkRequest request) { + log.info("validating project task id"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getSideEffects(); + Map> tenantIdSideEffectMap = entities.stream().collect(Collectors.groupingBy(SideEffect::getTenantId)); + tenantIdSideEffectMap.forEach((tenantId, sideEffects) -> { + List sideEffectList = tenantIdSideEffectMap.get(tenantId); + if (!sideEffectList.isEmpty()) { + List existingProjectBeneficiaries = null; + final List projectBeneficiaryIdList = new ArrayList<>(); + final List projectBeneficiaryClientReferenceIdList = new ArrayList<>(); + sideEffectList.forEach(sideEffect -> { + addIgnoreNull(projectBeneficiaryIdList, sideEffect.getProjectBeneficiaryId()); + addIgnoreNull(projectBeneficiaryClientReferenceIdList, sideEffect.getProjectBeneficiaryClientReferenceId()); + }); + ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() + .id(projectBeneficiaryIdList.isEmpty() ? null : projectBeneficiaryIdList) + .clientReferenceId(projectBeneficiaryClientReferenceIdList.isEmpty() ? null : projectBeneficiaryClientReferenceIdList) + .build(); + try { + BeneficiaryBulkResponse beneficiaryBulkResponse = serviceRequestClient.fetchResult( + new StringBuilder(referralManagementConfiguration.getProjectHost() + + referralManagementConfiguration.getProjectBeneficiarySearchUrl() + +"?limit=" + entities.size() + + "&offset=0&tenantId=" + tenantId), + BeneficiarySearchRequest.builder().requestInfo(request.getRequestInfo()).projectBeneficiary(projectBeneficiarySearch).build(), + BeneficiaryBulkResponse.class + ); + existingProjectBeneficiaries = beneficiaryBulkResponse.getProjectBeneficiaries(); + } catch (Exception e) { + throw new CustomException("Project Beneficiaries failed to fetch", "Exception : "+e.getMessage()); + } + final List existingProjectBeneficiaryIds = new ArrayList<>(); + final List existingProjectBeneficiaryClientReferenceIds = new ArrayList<>(); + existingProjectBeneficiaries.forEach(projectBeneficiary -> { + existingProjectBeneficiaryIds.add(projectBeneficiary.getId()); + existingProjectBeneficiaryClientReferenceIds.add(projectBeneficiary.getClientReferenceId()); + }); + /** + * for all the entities that do not have any error in previous validations + * checking whether the project beneficiary client reference id is not null and exist in the db + */ + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + ( Objects.nonNull(entity.getProjectBeneficiaryClientReferenceId()) + && !existingProjectBeneficiaryClientReferenceIds.contains(entity.getProjectBeneficiaryClientReferenceId()) ) + || ( Objects.nonNull(entity.getProjectBeneficiaryId()) + && !existingProjectBeneficiaryIds.contains(entity.getProjectBeneficiaryId()) ) + ).collect(Collectors.toList()); + invalidEntities.forEach(sideEffect -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(sideEffect, error, errorDetailsMap); + }); + } + }); + return errorDetailsMap; + } + private void addIgnoreNull(List list, String item) { + if(Objects.nonNull(item)) list.add(item); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java new file mode 100644 index 00000000000..20265333bb1 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java @@ -0,0 +1,108 @@ +package org.egov.referralmanagement.validator.sideeffect; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.project.Task; +import org.egov.common.models.project.TaskBulkResponse; +import org.egov.common.models.project.TaskSearch; +import org.egov.common.models.project.TaskSearchRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + +/** + * Validate whether project task exist in db or not using project task id and project task client beneficiary id for SideEffect object + */ +@Component +@Order(value = 3) +@Slf4j +public class SeProjectTaskIdValidator implements Validator { + private final ServiceRequestClient serviceRequestClient; + private final ReferralManagementConfiguration referralManagementConfiguration; + + @Autowired + public SeProjectTaskIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.referralManagementConfiguration = referralManagementConfiguration; + } + + + /** + * validating whether the project task id and client reference id exist or not in db + * return the invalid Side effect objects as error map + * + * @param request of SideEffectBulkRequest + * @return + */ + @Override + public Map> validate(SideEffectBulkRequest request) { + log.info("validating project task id"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getSideEffects(); + Map> tenantIdSideEffectMap = entities.stream().collect(Collectors.groupingBy(SideEffect::getTenantId)); + List tenantIds = new ArrayList<>(tenantIdSideEffectMap.keySet()); + tenantIds.forEach(tenantId -> { + List sideEffectList = tenantIdSideEffectMap.get(tenantId); + if (!sideEffectList.isEmpty()) { + List existingTasks = null; + final List taskIdList = new ArrayList<>(); + final List taskClientReferenceIdList = new ArrayList<>(); + sideEffectList.forEach(sideEffect -> { + addIgnoreNull(taskIdList, sideEffect.getTaskId()); + addIgnoreNull(taskClientReferenceIdList, sideEffect.getTaskClientReferenceId()); + }); + TaskSearch taskSearch = TaskSearch.builder() + .id(taskIdList.isEmpty() ? null : taskIdList) + .clientReferenceId(taskClientReferenceIdList.isEmpty() ? null : taskClientReferenceIdList).build(); + try { + TaskBulkResponse taskBulkResponse = serviceRequestClient.fetchResult( + new StringBuilder(referralManagementConfiguration.getProjectHost() + + referralManagementConfiguration.getProjectTaskSearchUrl() + +"?limit=" + entities.size() + + "&offset=0&tenantId=" + tenantId), + TaskSearchRequest.builder().requestInfo(request.getRequestInfo()).task(taskSearch).build(), + TaskBulkResponse.class + ); + existingTasks = taskBulkResponse.getTasks(); + } catch (Exception e) { + throw new CustomException("Project Task failed to fetch", "Exception : "+e.getMessage()); + } + final List existingProjectTaskIds = existingTasks.stream().map(Task::getId).collect(Collectors.toList()); + final List existingProjectReferenceTaskIds = existingTasks.stream().map(Task::getClientReferenceId).collect(Collectors.toList()); + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + !existingProjectReferenceTaskIds.contains(entity.getTaskClientReferenceId()) + && !existingProjectTaskIds.contains(entity.getTaskId()) + ).collect(Collectors.toList()); + invalidEntities.forEach(sideEffect -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(sideEffect, error, errorDetailsMap); + }); + + } + }); + + return errorDetailsMap; + } + + private void addIgnoreNull(List list, String item) { + if(Objects.nonNull(item)) list.add(item); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeRowVersionValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeRowVersionValidator.java new file mode 100644 index 00000000000..bc31412b97b --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeRowVersionValidator.java @@ -0,0 +1,86 @@ +package org.egov.referralmanagement.validator.sideeffect; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.repository.SideEffectRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.getEntitiesWithMismatchedRowVersion; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForRowVersionMismatch; + +/* +* +* Validator for checking row version consistency of SideEffect entities in a bulk request. +* It retrieves existing SideEffect entities from the repository, compares row versions, +* and populates error details for entities with mismatched row versions. +* +* @author syed-egov +* */ + +@Component +@Order(value = 5) +@Slf4j +public class SeRowVersionValidator implements Validator { + + private SideEffectRepository sideEffectRepository; + + @Autowired + public SeRowVersionValidator(SideEffectRepository sideEffectRepository) { + this.sideEffectRepository = sideEffectRepository; + } + + /* + * + * @param sideEffectBulkRequest The bulk request containing SideEffect entities to be validated. + * @return A map containing SideEffect entities with associated error details + * for entities with mismatched row versions. + * + */ + + @Override + public Map> validate(SideEffectBulkRequest sideEffectBulkRequest) { + log.info("validating row version"); + // Map to store SideEffect entities with associated error details + Map> errorDetailsMap = new HashMap<>(); + // Get the method used for obtaining entity IDs + Method idMethod = getIdMethod(sideEffectBulkRequest.getSideEffects()); + // Create a map of entity IDs to SideEffect entities for entities without errors + Map iMap = getIdToObjMap(sideEffectBulkRequest + .getSideEffects() + .stream() + .filter(notHavingErrors()) + .collect(Collectors.toList()),idMethod); + // Check if the map of IDs to SideEffect entities is not empty + if(!iMap.isEmpty()){ + List sideEffectIds = new ArrayList<>(iMap.keySet()); + // Retrieve existing SideEffect entities from the repository + List existingSideEffects = sideEffectRepository + .findById(sideEffectIds,false,getIdFieldName(idMethod)); + // Identify entities with mismatched row versions + List entitiesWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(iMap, existingSideEffects, idMethod); + // Populate error details for entities with mismatched row versions + entitiesWithMismatchedRowVersion.forEach(sideEffect -> { + Error error = getErrorForRowVersionMismatch(); + populateErrorDetails(sideEffect, error, errorDetailsMap); + }); + } + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java new file mode 100644 index 00000000000..90d4ffd633a --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java @@ -0,0 +1,47 @@ +package org.egov.referralmanagement.validator.sideeffect; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +@Component +@Order(value = 2) +@Slf4j +public class SeUniqueEntityValidator implements Validator { + + @Override + public Map> validate(SideEffectBulkRequest request) { + log.info("validating unique entity"); + Map> errorDetailsMap = new HashMap<>(); + List validEntities = request.getSideEffects() + .stream().filter(notHavingErrors()).collect(Collectors.toList()); + if (!validEntities.isEmpty()) { + Map eMap = getIdToObjMap(validEntities); + if (eMap.keySet().size() != validEntities.size()) { + List duplicates = eMap.keySet().stream().filter(id -> + validEntities.stream() + .filter(entity -> entity.getId().equals(id)).count() > 1 + ).collect(Collectors.toList()); + for (String key : duplicates) { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(eMap.get(key), error, errorDetailsMap); + } + } + } + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/BeneficiaryDownsyncController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/BeneficiaryDownsyncController.java new file mode 100644 index 00000000000..d780ef1cce0 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/BeneficiaryDownsyncController.java @@ -0,0 +1,54 @@ +package org.egov.referralmanagement.web.controllers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiParam; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.referralmanagement.beneficiarydownsync.Downsync; +import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncRequest; +import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncResponse; +import org.egov.common.utils.ResponseInfoFactory; +import org.egov.referralmanagement.service.DownsyncService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; + +@Slf4j +@Controller +@RequestMapping("/beneficiary-downsync") +@Validated +public class BeneficiaryDownsyncController { + + private DownsyncService downsyncService; + + private ObjectMapper mapper; + + @Autowired + BeneficiaryDownsyncController (DownsyncService downsyncService, @Qualifier("objectMapper") ObjectMapper objectMapper){ + this.downsyncService = downsyncService; + this.mapper = objectMapper; + } + + @PostMapping(value = "/v1/_get") + public ResponseEntity getBeneficaryData (@ApiParam(value = "Capture details of Side Effect", required = true) @Valid @RequestBody DownsyncRequest request) { + log.info("UserUUID: {}", request.getRequestInfo().getUserInfo().getUuid()); + log.info("Downsync RequestBody: {}", mapper.valueToTree(request).toString()); + Downsync.builder(). + downsyncCriteria(request.getDownsyncCriteria()) + .build(); + Downsync downsync = downsyncService.prepareDownsyncData(request); + DownsyncResponse response = DownsyncResponse.builder() + .downsync(downsync) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java new file mode 100644 index 00000000000..f09a4c578e8 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java @@ -0,0 +1,190 @@ +package org.egov.referralmanagement.web.controllers; + +import java.util.List; + +import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkResponse; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralRequest; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralResponse; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralSearchRequest; +import org.egov.common.producer.Producer; +import org.egov.common.utils.ResponseInfoFactory; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.service.HFReferralService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Controller class for managing HF Referrals. + * @author kanishq-egov + */ +@Controller +@RequestMapping("/hf-referral") +@Validated +public class HFReferralApiController { + private final HttpServletRequest httpServletRequest; + private final HFReferralService hfReferralService; + private final Producer producer; + private final ReferralManagementConfiguration referralManagementConfiguration; + + /** + * Constructor for HFReferralApiController. + * + * @param httpServletRequest The HTTP servlet request. + * @param hfReferralService The service for handling HFReferral operations. + * @param producer The Kafka producer. + * @param referralManagementConfiguration The configuration for referral management. + */ + public HFReferralApiController( + HttpServletRequest httpServletRequest, + HFReferralService hfReferralService, + Producer producer, + ReferralManagementConfiguration referralManagementConfiguration + ) { + this.httpServletRequest = httpServletRequest; + this.hfReferralService = hfReferralService; + this.producer = producer; + this.referralManagementConfiguration = referralManagementConfiguration; + } + + /** + * API endpoint to create a single HFReferral. + * + * @param request The HFReferralRequest containing referral details. + * @return ResponseEntity containing HFReferralResponse. + */ + @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) + public ResponseEntity referralV1CreatePost(@ApiParam(value = "Capture details of HFReferral", required = true) @Valid @RequestBody HFReferralRequest request) { + + HFReferral hfReferral = hfReferralService.create(request); + HFReferralResponse response = HFReferralResponse.builder() + .hfReferral(hfReferral) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } + + /** + * API endpoint to create multiple HFReferrals in bulk. + * + * @param request The HFReferralBulkRequest containing bulk referral details. + * @return ResponseEntity containing ResponseInfo. + */ + @RequestMapping(value = "/v1/bulk/_create", method = RequestMethod.POST) + public ResponseEntity referralBulkV1CreatePost(@ApiParam(value = "Capture details of HFReferral", required = true) @Valid @RequestBody HFReferralBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + hfReferralService.putInCache(request.getHfReferrals()); + producer.push(referralManagementConfiguration.getCreateHFReferralBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + + /** + * API endpoint to search for HFReferrals based on certain criteria. + * + * @param request The HFReferralSearchRequest containing search criteria. + * @return ResponseEntity containing HFReferralBulkResponse. + * @throws Exception + */ + @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) + public ResponseEntity referralV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "HFReferral Search.", required = true) @Valid @RequestBody HFReferralSearchRequest request + ) throws Exception { + + List hfReferrals = hfReferralService.search( + request, + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted()); + HFReferralBulkResponse response = HFReferralBulkResponse.builder().responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)).hfReferrals(hfReferrals).build(); + + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + /** + * API endpoint to update a single HFReferral. + * + * @param request The HFReferralRequest containing updated referral details. + * @return ResponseEntity containing HFReferralResponse. + */ + @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) + public ResponseEntity referralV1UpdatePost(@ApiParam(value = "Capture details of Existing HFReferral", required = true) @Valid @RequestBody HFReferralRequest request) { + HFReferral hfReferral = hfReferralService.update(request); + + HFReferralResponse response = HFReferralResponse.builder() + .hfReferral(hfReferral) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } + + /** + * API endpoint to update multiple HFReferrals in bulk. + * + * @param request The HFReferralBulkRequest containing bulk updated referral details. + * @return ResponseEntity containing ResponseInfo. + */ + @RequestMapping(value = "/v1/bulk/_update", method = RequestMethod.POST) + public ResponseEntity referralV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing HFReferral", required = true) @Valid @RequestBody HFReferralBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + producer.push(referralManagementConfiguration.getUpdateHFReferralBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + + /** + * API endpoint to delete a single HFReferral. + * + * @param request The HFReferralRequest containing details of the referral to be deleted. + * @return ResponseEntity containing HFReferralResponse. + */ + @RequestMapping(value = "/v1/_delete", method = RequestMethod.POST) + public ResponseEntity referralV1DeletePost(@ApiParam(value = "Capture details of Existing HFReferral", required = true) @Valid @RequestBody HFReferralRequest request) { + HFReferral hfReferral = hfReferralService.delete(request); + + HFReferralResponse response = HFReferralResponse.builder() + .hfReferral(hfReferral) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } + + /** + * API endpoint to delete multiple HFReferrals in bulk. + * + * @param request The HFReferralBulkRequest containing details of the referrals to be deleted in bulk. + * @return ResponseEntity containing ResponseInfo. + */ + @RequestMapping(value = "/v1/bulk/_delete", method = RequestMethod.POST) + public ResponseEntity referralV1BulkDeletePost(@ApiParam(value = "Capture details of Existing HFReferral", required = true) @Valid @RequestBody HFReferralBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + producer.push(referralManagementConfiguration.getDeleteHFReferralBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java new file mode 100644 index 00000000000..0d65d31d5c9 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java @@ -0,0 +1,173 @@ +package org.egov.referralmanagement.web.controllers; + +import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.referralmanagement.ReferralBulkResponse; +import org.egov.common.models.referralmanagement.ReferralRequest; +import org.egov.common.models.referralmanagement.ReferralResponse; +import org.egov.common.models.referralmanagement.ReferralSearchRequest; +import org.egov.common.producer.Producer; +import org.egov.common.utils.ResponseInfoFactory; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.service.ReferralManagementService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Referral Management Api Controller + */ +@Controller +@RequestMapping("") +@Validated +public class ReferralManagementApiController { + private final HttpServletRequest httpServletRequest; + + private final ReferralManagementService referralManagementService; + + private final Producer producer; + + private final ReferralManagementConfiguration referralManagementConfiguration; + + public ReferralManagementApiController( + HttpServletRequest httpServletRequest, + ReferralManagementService referralManagementService, + Producer producer, + ReferralManagementConfiguration referralManagementConfiguration + ) { + this.httpServletRequest = httpServletRequest; + this.referralManagementService = referralManagementService; + this.producer = producer; + this.referralManagementConfiguration = referralManagementConfiguration; + } + + /** + * @ + * @param request + * @return + */ + @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) + public ResponseEntity referralV1CreatePost(@ApiParam(value = "Capture details of Referral", required = true) @Valid @RequestBody ReferralRequest request) { + + Referral referral = referralManagementService.create(request); + ReferralResponse response = ReferralResponse.builder() + .referral(referral) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } + + + /** + * + * @param request + * @return + */ + @RequestMapping(value = "/v1/bulk/_create", method = RequestMethod.POST) + public ResponseEntity referralBulkV1CreatePost(@ApiParam(value = "Capture details of Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + referralManagementService.putInCache(request.getReferrals()); + producer.push(referralManagementConfiguration.getCreateReferralBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + + /** + * + * @param referralSearchRequest + * @return + * @throws Exception + */ + @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) + public ResponseEntity referralV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Referral Search.", required = true) @Valid @RequestBody ReferralSearchRequest referralSearchRequest + ) throws Exception { + + SearchResponse referralSearchResponse = referralManagementService.search( + referralSearchRequest, + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted()); + ReferralBulkResponse response = ReferralBulkResponse.builder().responseInfo(ResponseInfoFactory + .createResponseInfo(referralSearchRequest.getRequestInfo(), true)) + .referrals(referralSearchResponse.getResponse()) + .totalCount(referralSearchResponse.getTotalCount()) + .build(); + + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + /** + * + * @param request + * @return + */ + @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) + public ResponseEntity referralV1UpdatePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralRequest request) { + Referral referral = referralManagementService.update(request); + + ReferralResponse response = ReferralResponse.builder() + .referral(referral) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + + } + + /** + * + * @param request + * @return + */ + @RequestMapping(value = "/v1/bulk/_update", method = RequestMethod.POST) + public ResponseEntity referralV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + producer.push(referralManagementConfiguration.getUpdateReferralBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + + @RequestMapping(value = "/v1/_delete", method = RequestMethod.POST) + public ResponseEntity referralV1DeletePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralRequest request) { + Referral referral = referralManagementService.delete(request); + + ReferralResponse response = ReferralResponse.builder() + .referral(referral) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + + } + + @RequestMapping(value = "/v1/bulk/_delete", method = RequestMethod.POST) + public ResponseEntity referralV1BulkDeletePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + producer.push(referralManagementConfiguration.getDeleteReferralBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java new file mode 100644 index 00000000000..65b777c9a1f --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java @@ -0,0 +1,144 @@ +package org.egov.referralmanagement.web.controllers; + +import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkResponse; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectResponse; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; +import org.egov.common.producer.Producer; +import org.egov.common.utils.ResponseInfoFactory; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.service.SideEffectService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +@Controller +@RequestMapping("/side-effect") +@Validated +public class SideEffectApiController { + + private final HttpServletRequest httpServletRequest; + + private final SideEffectService sideEffectService; + + private final Producer producer; + + private final ReferralManagementConfiguration referralManagementConfiguration; + + public SideEffectApiController( + HttpServletRequest httpServletRequest, + SideEffectService sideEffectService, + Producer producer, + ReferralManagementConfiguration referralManagementConfiguration + ) { + this.httpServletRequest = httpServletRequest; + this.sideEffectService = sideEffectService; + this.producer = producer; + this.referralManagementConfiguration = referralManagementConfiguration; + } + + @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) + public ResponseEntity sideEffectV1CreatePost(@ApiParam(value = "Capture details of Side Effect", required = true) @Valid @RequestBody SideEffectRequest request) { + + SideEffect sideEffect = sideEffectService.create(request); + SideEffectResponse response = SideEffectResponse.builder() + .sideEffect(sideEffect) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } + + + + @RequestMapping(value = "/v1/bulk/_create", method = RequestMethod.POST) + public ResponseEntity sideEffectBulkV1CreatePost(@ApiParam(value = "Capture details of Side Effect", required = true) @Valid @RequestBody SideEffectBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + sideEffectService.putInCache(request.getSideEffects()); + producer.push(referralManagementConfiguration.getCreateSideEffectBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + + @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) + public ResponseEntity sideEffectV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Side Effect Search.", required = true) @Valid @RequestBody SideEffectSearchRequest request + ) throws Exception { + + SearchResponse sideEffectSearchResponse = sideEffectService.search( + request, + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() + ); + SideEffectBulkResponse response = SideEffectBulkResponse.builder().responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)).sideEffects(sideEffectSearchResponse.getResponse()) + .totalCount(sideEffectSearchResponse.getTotalCount()).build(); + + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) + public ResponseEntity sideEffectV1UpdatePost(@ApiParam(value = "Capture details of Existing side effect", required = true) @Valid @RequestBody SideEffectRequest request) { + SideEffect sideEffect = sideEffectService.update(request); + + SideEffectResponse response = SideEffectResponse.builder() + .sideEffect(sideEffect) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + + } + + @RequestMapping(value = "/v1/bulk/_update", method = RequestMethod.POST) + public ResponseEntity sideEffectV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing side effect", required = true) @Valid @RequestBody SideEffectBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + producer.push(referralManagementConfiguration.getUpdateSideEffectBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + + @RequestMapping(value = "/v1/_delete", method = RequestMethod.POST) + public ResponseEntity sideEffectV1DeletePost(@ApiParam(value = "Capture details of Existing side effect", required = true) @Valid @RequestBody SideEffectRequest request) { + SideEffect sideEffect = sideEffectService.delete(request); + + SideEffectResponse response = SideEffectResponse.builder() + .sideEffect(sideEffect) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + + } + + @RequestMapping(value = "/v1/bulk/_delete", method = RequestMethod.POST) + public ResponseEntity sideEffectV1BulkDeletePost(@ApiParam(value = "Capture details of Existing side effect", required = true) @Valid @RequestBody SideEffectBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + producer.push(referralManagementConfiguration.getDeleteSideEffectBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } +} diff --git a/health-services/referralmanagement/src/main/resources/application.properties b/health-services/referralmanagement/src/main/resources/application.properties new file mode 100644 index 00000000000..b7ac09656ac --- /dev/null +++ b/health-services/referralmanagement/src/main/resources/application.properties @@ -0,0 +1,158 @@ +server.servlet.context-path=/referralmanagement +server.port=8082 +app.timezone=UTC + +# REDIS CONFIG +spring.redis.host=localhost +spring.redis.port=6379 +spring.cache.type=redis +# Seconds +spring.cache.redis.time-to-live=60 +spring.cache.autoexpiry=true + +# DATABASE CONFIG +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/postgres +spring.datasource.username=postgres +spring.datasource.password=postgres + +# FLYWAY CONFIG +spring.flyway.url=jdbc:postgresql://localhost:5432/postgres +spring.flyway.user=postgres +spring.flyway.password=postgres +spring.flyway.table=public +spring.flyway.baseline-on-migrate=true +spring.flyway.outOfOrder=true +spring.flyway.locations=classpath:/db/migration/main +spring.flyway.enabled=false + +# TRACER CONFIG +# KAFKA SERVER CONFIG +kafka.config.bootstrap_server_config=localhost:9092 +spring.kafka.consumer.value-deserializer=org.egov.tracer.kafka.deserializer.HashMapDeserializer +spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer +spring.kafka.consumer.group-id=project +spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer +spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer +spring.kafka.listener.missing-topics-fatal=false +spring.kafka.consumer.properties.spring.json.use.type.headers=false + +# KAFKA CONSUMER CONFIG +kafka.consumer.config.auto_commit=true +kafka.consumer.config.auto_commit_interval=100 +kafka.consumer.config.session_timeout=15000 +kafka.consumer.config.auto_offset_reset=earliest + +# KAFKA PRODUCER CONFIG +kafka.producer.config.retries_config=0 +kafka.producer.config.batch_size_config=16384 +kafka.producer.config.linger_ms_config=1 +kafka.producer.config.buffer_memory_config=33554432 + +# IDGEN CONFIG +# egov.idgen.host=https://dev.digit.org/ +#egov.idgen.host=https://health-dev.digit.org/ +egov.idgen.host=http://localhost:8081/ +egov.idgen.path=egov-idgen/id/_generate +egov.idgen.integration.enabled=true +referralmanagement.sideeffect.idgen.id.format=referralmanagement.sideeffect.id +referralmanagement.referral.idgen.id.format=referralmanagement.referral.id +idgen.project.beneficiary.id.format=project.beneficiary.id +project.staff.idgen.id.format=project.staff.id +project.facility.idgen.id.format=project.facility.id +egov.idgen.project.number.name=project.number +project.resource.idgen.id.format=project.resource.id + +# The value of the following field should be changed to service specific name +kafka.topics.consumer=project-consumer-topic + +# USER CONFIG +egov.user.host=https://unified-dev.digit.org +#egov.user.host=http://localhost:8286 +egov.search.user.url=/user/_search +egov.user.integration.enabled=true + +# MDMS CONFIG +egov.mdms.host=https://unified-dev.digit.org +egov.mdms.search.endpoint=/egov-mdms-service/v1/_search +egov.mdms.master.name=project_master +egov.mdms.module.name=project +egov.mdms.integration.enabled=true + +# FACILITY SERVICE +egov.facility.host=http://localhost:8083 +egov.search.facility.url=/facility/v1/_search + +# HOUSEHOLD SERVICE +egov.household.host=http://localhost:8081 +egov.search.household.url=/household/v1/_search +egov.search.household.member.url=/household/member/v1/_search + +# INDIVIDUAL SERVICE +egov.individual.host=http://localhost:8086 +egov.search.individual.url=/individual/v1/_search + +# use the value as "egov-user" to validate against egov-user service +# use the value as "individual" to validate against individual service +egov.user.id.validator=individual + +# PROJECT SERVICE +egov.project.host=https://unified-dev.digit.org +egov.search.project.url=/project/v1/_search +egov.search.project.task.url=/project/task/v1/_search +egov.search.project.beneficiary.url=/project/beneficiary/v1/_search +egov.search.project.staff.url=/project/staff/v1/_search +egov.search.project.facility.url=/project/facility/v1/_search + + +# ADRM KAFKA CONFIG +referralmanagement.sideeffect.kafka.create.topic=save-side-effect-topic +referralmanagement.sideeffect.kafka.update.topic=update-side-effect-topic +referralmanagement.sideeffect.kafka.delete.topic=delete-side-effect-topic + +referralmanagement.sideeffect.consumer.bulk.create.topic=save-side-effect-bulk-topic +referralmanagement.sideeffect.consumer.bulk.update.topic=update-side-effect-bulk-topic +referralmanagement.sideeffect.consumer.bulk.delete.topic=delete-side-effect-bulk-topic + +referralmanagement.referral.kafka.create.topic=save-referral-topic +referralmanagement.referral.kafka.update.topic=update-referral-topic +referralmanagement.referral.kafka.delete.topic=delete-referral-topic + +referralmanagement.referral.consumer.bulk.create.topic=save-referral-bulk-topic +referralmanagement.referral.consumer.bulk.update.topic=update-referral-bulk-topic +referralmanagement.referral.consumer.bulk.delete.topic=delete-referral-bulk-topic + +referralmanagement.hfreferral.kafka.create.topic=save-hfreferral-topic +referralmanagement.hfreferral.kafka.update.topic=update-hfreferral-topic +referralmanagement.hfreferral.kafka.delete.topic=delete-hfreferral-topic + +referralmanagement.hfreferral.consumer.bulk.create.topic=save-hfreferral-bulk-topic +referralmanagement.hfreferral.consumer.bulk.update.topic=update-hfreferral-bulk-topic +referralmanagement.hfreferral.consumer.bulk.delete.topic=delete-hfreferral-bulk-topic + +search.api.limit=1000 + +referralmanagement.default.offset=0 +referralmanagement.default.limit=100 +referralmanagement.search.max.limit=200 + + +#location config +egov.location.host=https://works-dev.digit.org +egov.location.context.path=/egov-location/location/v11/ +egov.location.endpoint=/boundarys/_search +egov.location.code.query.param=codes + +#user config +egov.create.user.url=/user/_create +egov.update.user.url=/user/_update + +project.document.id.verification.required=false + + +project.mdms.module=HCM-PROJECT-TYPES +egov.location.hierarchy.type=ADMIN + + + + diff --git a/health-services/referralmanagement/src/main/resources/db/Dockerfile b/health-services/referralmanagement/src/main/resources/db/Dockerfile new file mode 100644 index 00000000000..e7da01d7f0b --- /dev/null +++ b/health-services/referralmanagement/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"] \ No newline at end of file diff --git a/health-services/referralmanagement/src/main/resources/db/migrate.sh b/health-services/referralmanagement/src/main/resources/db/migrate.sh new file mode 100644 index 00000000000..f9d6617822c --- /dev/null +++ b/health-services/referralmanagement/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 diff --git a/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928113400__referral_create_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928113400__referral_create_ddl.sql new file mode 100644 index 00000000000..b17f93e6ee5 --- /dev/null +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928113400__referral_create_ddl.sql @@ -0,0 +1,26 @@ +CREATE TABLE REFERRAL +( + id character varying(64), + clientReferenceId character varying(64), + tenantId character varying(1000), + projectBeneficiaryId character varying(64), + projectBeneficiaryClientReferenceId character varying(64), + referrerId character varying(100), + recipientId character varying(100), + recipientType character varying(100), + reasons jsonb, + sideEffectId character varying(100), + sideEffectClientReferenceId character varying(100), + createdBy character varying(64), + createdTime bigint, + lastModifiedBy character varying(64), + lastModifiedTime bigint, + clientCreatedBy character varying(64), + clientCreatedTime bigint, + clientLastModifiedBy character varying(64), + clientLastModifiedTime bigint, + rowVersion bigint, + isDeleted boolean, + CONSTRAINT uk_referral_id PRIMARY KEY (id), + CONSTRAINT uk_referral_clientReferenceId UNIQUE (clientReferenceId) +); diff --git a/health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql new file mode 100644 index 00000000000..2cb20d2a998 --- /dev/null +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql @@ -0,0 +1,22 @@ +CREATE TABLE IF NOT EXISTS SIDE_EFFECT( + id character varying(64), + clientReferenceId character varying(64) NOT NULL, + tenantId character varying(1000), + taskId character varying(64), + taskClientReferenceId character varying(64) NOT NULL, + projectBeneficiaryId character varying(64), + projectBeneficiaryClientReferenceId character varying(64), + symptoms jsonb, + createdBy character varying(64), + createdTime bigint, + lastModifiedBy character varying(64), + lastModifiedTime bigint, + clientCreatedBy character varying(64), + clientCreatedTime bigint, + clientLastModifiedBy character varying(64), + clientLastModifiedTime bigint, + rowVersion bigint, + isDeleted bool, + CONSTRAINT uk_side_effect PRIMARY KEY (id), + CONSTRAINT uk_side_effect_clientReference_id unique (clientReferenceId) +); \ No newline at end of file diff --git a/health-services/referralmanagement/src/main/resources/db/migration/main/V20231019114100__referral_side_effect_additionaldetails_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20231019114100__referral_side_effect_additionaldetails_ddl.sql new file mode 100644 index 00000000000..9cf29e89062 --- /dev/null +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20231019114100__referral_side_effect_additionaldetails_ddl.sql @@ -0,0 +1,2 @@ +ALTER TABLE side_effect ADD COLUMN IF NOT EXISTS additionalDetails jsonb; +ALTER TABLE referral ADD COLUMN IF NOT EXISTS additionalDetails jsonb; \ No newline at end of file diff --git a/health-services/referralmanagement/src/main/resources/db/migration/main/V20231214113400__hf_referral_create_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20231214113400__hf_referral_create_ddl.sql new file mode 100644 index 00000000000..0d4dfbd4dad --- /dev/null +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20231214113400__hf_referral_create_ddl.sql @@ -0,0 +1,25 @@ +CREATE table IF NOT EXISTS hf_referral ( + id character varying(64), + clientreferenceid character varying(64), + tenantid character varying(1000), + projectid character varying(64), + facilityId character varying(64), + symptom character varying(256), + symptomsurveyid character varying(100), + beneficiaryid character varying(100), + referralcode character varying(100), + nationallevelid character varying(100), + createdby character varying(64), + createdtime bigint, + lastmodifiedby character varying(64), + lastmodifiedtime bigint, + clientcreatedby character varying(64), + clientcreatedtime bigint, + clientlastmodifiedby character varying(64), + clientlastmodifiedtime bigint, + rowversion bigint, + isdeleted boolean, + additionaldetails jsonb, + CONSTRAINT uk_hf_referral_id PRIMARY KEY (id), + CONSTRAINT uk_hf_referral_clientReferenceId UNIQUE (clientReferenceId) +); \ No newline at end of file diff --git a/health-services/referralmanagement/src/main/resources/db/migration/main/V20240103142200__hf_referral_project_facility_rename_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20240103142200__hf_referral_project_facility_rename_ddl.sql new file mode 100644 index 00000000000..f7a8fb9b884 --- /dev/null +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20240103142200__hf_referral_project_facility_rename_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE hf_referral RENAME COLUMN facilityid to projectfacilityid; \ No newline at end of file diff --git a/health-services/referralmanagement/src/main/resources/db/migration/main/V20240416111000__referral_referral_code_create_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20240416111000__referral_referral_code_create_ddl.sql new file mode 100644 index 00000000000..23a174ce793 --- /dev/null +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20240416111000__referral_referral_code_create_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE REFERRAL ADD COLUMN referralCode character varying(256); \ No newline at end of file diff --git a/health-services/referralmanagement/src/main/resources/referral-management-persister.yml b/health-services/referralmanagement/src/main/resources/referral-management-persister.yml new file mode 100644 index 00000000000..de72b595fa9 --- /dev/null +++ b/health-services/referralmanagement/src/main/resources/referral-management-persister.yml @@ -0,0 +1,158 @@ +serviceMaps: + serviceName: referralmanagement + mappings: + - version: 1.0 + description: Saves a side effect + fromTopic: save-side-effect-topic + isTransaction: true + queryMaps: + - query: INSERT INTO SIDE_EFFECT(id, clientReferenceId, tenantId, taskId, taskClientReferenceId, projectBeneficiaryId, projectBeneficiaryClientReferenceId, symptoms, additionalDetails, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedBy, clientCreatedTime, clientLastModifiedBy, clientLastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); + basePath: $.* + jsonMaps: + - jsonPath: $.*.id + - jsonPath: $.*.clientReferenceId + - jsonPath: $.*.tenantId + - jsonPath: $.*.taskId + - jsonPath: $.*.taskClientReferenceId + - jsonPath: $.*.projectBeneficiaryId + - jsonPath: $.*.projectBeneficiaryClientReferenceId + - jsonPath: $.*.symptoms + type: JSON + dbType: JSONB + - jsonPath: $.*.additionalFields + type: JSON + dbType: JSONB + - jsonPath: $.*.auditDetails.createdBy + - jsonPath: $.*.auditDetails.createdTime + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.createdBy + - jsonPath: $.*.clientAuditDetails.createdTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + + - version: 1.0 + description: Updates a side effect + fromTopic: update-side-effect-topic + isTransaction: true + queryMaps: + - query: UPDATE SIDE_EFFECT SET tenantId = ?, taskId = ?, taskClientReferenceId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, symptoms = ?, additionalDetails = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.tenantId + - jsonPath: $.*.taskId + - jsonPath: $.*.taskClientReferenceId + - jsonPath: $.*.projectBeneficiaryId + - jsonPath: $.*.projectBeneficiaryClientReferenceId + - jsonPath: $.*.symptoms + type: JSON + dbType: JSONB + - jsonPath: $.*.additionalFields + type: JSON + dbType: JSONB + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id + + - version: 1.0 + description: Deletes a side effect + fromTopic: delete-side-effect-topic + isTransaction: true + queryMaps: + - query: UPDATE SIDE_EFFECT SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id + + - version: 1.0 + description: Saves a referral + fromTopic: save-referral-topic + isTransaction: true + queryMaps: + - query: INSERT INTO REFERRAL(id, clientReferenceId, tenantId, projectBeneficiaryId, projectBeneficiaryClientReferenceId, referrerId, recipientId, recipientType, reasons, additionalDetails, sideEffectId, sideEffectClientReferenceId, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedBy, clientCreatedTime, clientLastModifiedBy, clientLastModifiedTime, rowVersion, isDeleted) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); + basePath: $.* + jsonMaps: + - jsonPath: $.*.id + - jsonPath: $.*.clientReferenceId + - jsonPath: $.*.tenantId + - jsonPath: $.*.projectBeneficiaryId + - jsonPath: $.*.projectBeneficiaryClientReferenceId + - jsonPath: $.*.referrerId + - jsonPath: $.*.recipientId + - jsonPath: $.*.recipientType + - jsonPath: $.*.reasons + type: JSON + dbType: JSONB + - jsonPath: $.*.additionalFields + type: JSON + dbType: JSONB + - jsonPath: $.*.sideEffect.id + - jsonPath: $.*.sideEffect.clientReferenceId + - jsonPath: $.*.auditDetails.createdBy + - jsonPath: $.*.auditDetails.createdTime + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.createdBy + - jsonPath: $.*.clientAuditDetails.createdTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + + - version: 1.0 + description: Updates a referral + fromTopic: update-referral-topic + isTransaction: true + queryMaps: + - query: UPDATE REFERRAL SET tenantId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, referrerId = ?, recipientId = ?, recipientType = ?, reasons = ?, additionalDetails = ?, sideEffectId = ?, sideEffectClientReferenceId = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.tenantId + - jsonPath: $.*.projectBeneficiaryId + - jsonPath: $.*.projectBeneficiaryClientReferenceId + - jsonPath: $.*.referrerId + - jsonPath: $.*.recipientId + - jsonPath: $.*.recipientType + - jsonPath: $.*.reasons + type: JSON + dbType: JSONB + - jsonPath: $.*.additionalFields + type: JSON + dbType: JSONB + - jsonPath: $.*.sideEffect.id + - jsonPath: $.*.sideEffect.clientReferenceId + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id + + - version: 1.0 + description: Deletes a referral + fromTopic: delete-referral-topic + isTransaction: true + queryMaps: + - query: UPDATE REFERRAL SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id \ No newline at end of file diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/AppTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/AppTest.java new file mode 100644 index 00000000000..9b872dba7b8 --- /dev/null +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/AppTest.java @@ -0,0 +1,21 @@ +package org.egov.referralmanagement; + + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Unit test for simple App. + */ +public class AppTest +{ + /** + * Rigorous Test :-) + */ + @Test + public void shouldAnswerWithTrue() + { + assertTrue( true ); + } +} diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/TestConfiguration.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/TestConfiguration.java new file mode 100644 index 00000000000..c27d6693d1c --- /dev/null +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/TestConfiguration.java @@ -0,0 +1,16 @@ +package org.egov.referralmanagement; + +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/referralmanagement/src/test/java/org/egov/referralmanagement/helper/ReferralRequestTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/ReferralRequestTestBuilder.java new file mode 100644 index 00000000000..d9e7c9ba034 --- /dev/null +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/ReferralRequestTestBuilder.java @@ -0,0 +1,60 @@ +package org.egov.referralmanagement.helper; + +import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.referralmanagement.ReferralRequest; + +import java.util.ArrayList; + +public class ReferralRequestTestBuilder { + private ReferralRequest.ReferralRequestBuilder builder; + + private ArrayList referral = new ArrayList(); + + public ReferralRequestTestBuilder() { + this.builder = ReferralRequest.builder(); + } + + public static ReferralRequestTestBuilder builder() { + return new ReferralRequestTestBuilder(); + } + + public ReferralRequest build() { + return this.builder.build(); + } + + public ReferralRequestTestBuilder withOneReferral() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .referral(ReferralTestBuilder.builder().withId().withAuditDetails().build()); + return this; + } + + public ReferralRequestTestBuilder withApiOperationNotNullAndNotCreate() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .referral(ReferralTestBuilder.builder().withIdNull().build()); + return this; + } + + public ReferralRequestTestBuilder withApiOperationNotUpdate() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .referral(ReferralTestBuilder.builder().withIdNull().build()); + return this; + } + + public ReferralRequestTestBuilder withOneReferralHavingId() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .referral(ReferralTestBuilder.builder().withId().withAuditDetails().build()); + return this; + } + + public ReferralRequestTestBuilder withBadTenantIdInOneReferral() { + + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .referral(ReferralTestBuilder.builder().withIdNull().withBadTenantId().build()); + return this; + } + + public ReferralRequestTestBuilder withRequestInfo(){ + this.builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()); + return this; + } +} diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/ReferralTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/ReferralTestBuilder.java new file mode 100644 index 00000000000..1f2dfd310d9 --- /dev/null +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/ReferralTestBuilder.java @@ -0,0 +1,78 @@ +package org.egov.referralmanagement.helper; + +import org.egov.common.helper.AuditDetailsTestBuilder; +import org.egov.common.models.referralmanagement.Referral; + +import java.util.ArrayList; +import java.util.Arrays; + +public class ReferralTestBuilder { + + private Referral.ReferralBuilder builder; + + public ReferralTestBuilder() { + this.builder = (Referral.ReferralBuilder) Referral.builder(); + } + + public static ReferralTestBuilder builder() { + return new ReferralTestBuilder(); + } + + public Referral build() { + return this.builder.hasErrors(false).build(); + } + + public ReferralTestBuilder withIdNull() { + this.builder.projectBeneficiaryId("some-projectBeneficiary-id") + .clientReferenceId("ClientReferenceId") + .id(null) + .projectBeneficiaryClientReferenceId("projectBeneficiaryClientReferenceId") + .reasons(new ArrayList<>(Arrays.asList("fever"))) + .tenantId("some-tenant-id") + .rowVersion(1); + return this; + } + + public ReferralTestBuilder withId() { + withIdNull().builder.id("some-id") + .projectBeneficiaryId("some-projectBeneficiary-id") + .clientReferenceId("ClientReferenceId") + .projectBeneficiaryClientReferenceId("projectBeneficiaryClientReferenceId") + .reasons(new ArrayList<>(Arrays.asList("fever"))) + .tenantId("some-tenant-id") + .rowVersion(1); + return this; + } + + public ReferralTestBuilder withId(String id) { + this.builder.id(id); + return this; + } + + public ReferralTestBuilder withBadTenantId() { + this.builder.tenantId(null); + return this; + } + + public ReferralTestBuilder goodReferral() { + this.builder.id("some-id") + .projectBeneficiaryId("some-projectBeneficiary-id") + .clientReferenceId("ClientReferenceId") + .projectBeneficiaryClientReferenceId("projectBeneficiaryClientReferenceId") + .reasons(new ArrayList<>(Arrays.asList("fever"))) + .tenantId("some-tenant-id") + .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()) + .clientAuditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); + return this; + } + + public ReferralTestBuilder withAuditDetails() { + this.builder.auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); + return this; + } + + public ReferralTestBuilder withDeleted() { + this.builder.isDeleted(true); + return this; + } +} diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectRequestTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectRequestTestBuilder.java new file mode 100644 index 00000000000..d5bf7a9195c --- /dev/null +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectRequestTestBuilder.java @@ -0,0 +1,60 @@ +package org.egov.referralmanagement.helper; + +import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectRequest; + +import java.util.ArrayList; + +public class SideEffectRequestTestBuilder { + private SideEffectRequest.SideEffectRequestBuilder builder; + + private ArrayList sideEffect = new ArrayList(); + + public SideEffectRequestTestBuilder() { + this.builder = SideEffectRequest.builder(); + } + + public static SideEffectRequestTestBuilder builder() { + return new SideEffectRequestTestBuilder(); + } + + public SideEffectRequest build() { + return this.builder.build(); + } + + public SideEffectRequestTestBuilder withOneSideEffect() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .sideEffect(SideEffectTestBuilder.builder().withId().withAuditDetails().build()); + return this; + } + + public SideEffectRequestTestBuilder withApiOperationNotNullAndNotCreate() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .sideEffect(SideEffectTestBuilder.builder().withIdNull().build()); + return this; + } + + public SideEffectRequestTestBuilder withApiOperationNotUpdate() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .sideEffect(SideEffectTestBuilder.builder().withIdNull().build()); + return this; + } + + public SideEffectRequestTestBuilder withOneSideEffectHavingId() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .sideEffect(SideEffectTestBuilder.builder().withId().withAuditDetails().build()); + return this; + } + + public SideEffectRequestTestBuilder withBadTenantIdInOneSideEffect() { + + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .sideEffect(SideEffectTestBuilder.builder().withIdNull().withBadTenantId().build()); + return this; + } + + public SideEffectRequestTestBuilder withRequestInfo(){ + this.builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()); + return this; + } +} diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java new file mode 100644 index 00000000000..e2adc35eb3f --- /dev/null +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java @@ -0,0 +1,76 @@ +package org.egov.referralmanagement.helper; + +import org.egov.common.helper.AuditDetailsTestBuilder; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; + +import java.util.ArrayList; +import java.util.Arrays; + +public class SideEffectTestBuilder { + + private SideEffect.SideEffectBuilder builder; + + public SideEffectTestBuilder() { + this.builder = (SideEffect.SideEffectBuilder) SideEffect.builder(); + } + + public static SideEffectTestBuilder builder() { + return new SideEffectTestBuilder(); + } + + public SideEffect build() { + return this.builder.hasErrors(false).build(); + } + + public SideEffectTestBuilder withIdNull() { + this.builder.taskId("some-task-id") + .clientReferenceId("sideEffectClientReferenceId") + .id(null) + .taskClientReferenceId("null") + .symptoms(new ArrayList<>(Arrays.asList("fever"))) + .tenantId("some-tenant-id") + .rowVersion(1); + return this; + } + + public SideEffectTestBuilder withId() { + withIdNull().builder.id("some-id").taskId("some-task-id") + .clientReferenceId("sideEffectClientReferenceId") + .taskClientReferenceId("null") + .symptoms(new ArrayList<>(Arrays.asList("fever"))) + .tenantId("some-tenant-id"); + return this; + } + + public SideEffectTestBuilder withId(String id) { + this.builder.id(id); + return this; + } + + public SideEffectTestBuilder withBadTenantId() { + this.builder.tenantId(null); + return this; + } + + public SideEffectTestBuilder goodSideEffect() { + this.builder.id("some-id").taskId("some-task-id") + .clientReferenceId("sideEffectClientReferenceId") + .taskClientReferenceId("null") + .symptoms(new ArrayList<>(Arrays.asList("fever"))) + .tenantId("some-tenant-id") + .rowVersion(1) + .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()) + .clientAuditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); + return this; + } + + public SideEffectTestBuilder withAuditDetails() { + this.builder.auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); + return this; + } + + public SideEffectTestBuilder withDeleted() { + this.builder.isDeleted(true); + return this; + } +} diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java new file mode 100644 index 00000000000..81c5a664f1f --- /dev/null +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java @@ -0,0 +1,213 @@ +package org.egov.referralmanagement.web.controllers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkResponse; +import org.egov.common.models.referralmanagement.ReferralRequest; +import org.egov.common.models.referralmanagement.ReferralResponse; +import org.egov.common.models.referralmanagement.ReferralSearch; +import org.egov.common.models.referralmanagement.ReferralSearchRequest; +import org.egov.common.producer.Producer; +import org.egov.referralmanagement.TestConfiguration; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.helper.ReferralRequestTestBuilder; +import org.egov.referralmanagement.helper.ReferralTestBuilder; +import org.egov.referralmanagement.service.ReferralManagementService; +import org.egov.tracer.model.CustomException; +import org.egov.tracer.model.ErrorRes; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@WebMvcTest(ReferralManagementApiController.class) +@Import(TestConfiguration.class) +public class ReferralManagementApiControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private ReferralManagementService referralManagementService; + + @MockBean + private Producer producer; + + @MockBean + ReferralManagementConfiguration referralManagementConfiguration; + + @Test + @DisplayName("should create referral and return with 202 accepted") + void shouldCreateReferralAndReturnWith202Accepted() throws Exception { + ReferralRequest request = ReferralRequestTestBuilder.builder() + .withOneReferral() + .withApiOperationNotUpdate() + .build(); + List referrals = getReferrals(); + Mockito.when(referralManagementService.create(ArgumentMatchers.any(ReferralRequest.class))).thenReturn(referrals.get(0)); + + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/v1/_create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(MockMvcResultMatchers.status().isAccepted()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ReferralResponse response = objectMapper.readValue(responseStr, ReferralResponse.class); + + Assertions.assertNotNull(response.getReferral()); + Assertions.assertNotNull(response.getReferral().getId()); + Assertions.assertEquals("successful", response.getResponseInfo().getStatus()); + } + + private List getReferrals() { + Referral referral = ReferralTestBuilder.builder().withId().build(); + List referrals = new ArrayList<>(); + referrals.add(referral); + return referrals; + } + + + @Test + @DisplayName("should send error response with error details with 400 bad request for create") + void shouldSendErrorResWithErrorDetailsWith400BadRequestForCreate() throws Exception { + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/v1/_create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(ReferralRequestTestBuilder.builder() + .withOneReferral() + .withBadTenantIdInOneReferral() + .build()))) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ErrorRes response = objectMapper.readValue(responseStr, ErrorRes.class); + + Assertions.assertEquals(1, response.getErrors().size()); + Assertions.assertTrue(response.getErrors().get(0).getCode().contains("tenantId")); + } + + @Test + @DisplayName("should update referral and return with 202 accepted") + void shouldUpdateReferralAndReturnWith202Accepted() throws Exception { + ReferralRequest request = ReferralRequestTestBuilder.builder() + .withOneReferralHavingId() + .withApiOperationNotNullAndNotCreate() + .build(); + Referral referral = ReferralTestBuilder.builder().withId().build(); + Mockito.when(referralManagementService.update(ArgumentMatchers.any(ReferralRequest.class))).thenReturn(referral); + + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/v1/_update") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(MockMvcResultMatchers.status().isAccepted()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ReferralResponse response = objectMapper.readValue(responseStr, ReferralResponse.class); + + Assertions.assertNotNull(response.getReferral()); + Assertions.assertNotNull(response.getReferral().getId()); + Assertions.assertEquals("successful", response.getResponseInfo().getStatus()); + } + + @Test + @DisplayName("should send error response with error details with 400 bad request for update") + void shouldSendErrorResWithErrorDetailsWith400BadRequestForUpdate() throws Exception { + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/v1/_update") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(ReferralRequestTestBuilder.builder() + .withOneReferralHavingId() + .withBadTenantIdInOneReferral() + .build()))) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ErrorRes response = objectMapper.readValue(responseStr, + ErrorRes.class); + + Assertions.assertEquals(1, response.getErrors().size()); + Assertions.assertTrue(response.getErrors().get(0).getCode().contains("tenantId")); + } + + @Test + @DisplayName("Should accept search request and return response as accepted") + void shouldAcceptSearchRequestAndReturnReferral() throws Exception { + + ReferralSearchRequest referralSearchRequest = ReferralSearchRequest.builder().referral( + ReferralSearch.builder().projectBeneficiaryId(Arrays.asList("some-project-beneficiary-id")).build() + ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); + + Mockito.when(referralManagementService.search(ArgumentMatchers.any(ReferralSearchRequest.class), + ArgumentMatchers.any(Integer.class), + ArgumentMatchers.any(Integer.class), + ArgumentMatchers.any(String.class), + ArgumentMatchers.any(Long.class), + ArgumentMatchers.any(Boolean.class))).thenReturn( + SearchResponse.builder() + .response(Arrays.asList(ReferralTestBuilder.builder().withId().withAuditDetails().build())) + .build() + ); + + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post( + "/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(referralSearchRequest))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ReferralBulkResponse response = objectMapper.readValue(responseStr, + ReferralBulkResponse.class); + + Assertions.assertEquals(response.getReferrals().size(), 1); + } + + @Test + @DisplayName("Should accept search request and return response as accepted") + void shouldThrowExceptionIfNoResultFound() throws Exception { + + ReferralSearchRequest referralSearchRequest = ReferralSearchRequest.builder().referral( + ReferralSearch.builder().projectBeneficiaryId(Arrays.asList("some-project-beneficiary-id")).build() + ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); + + Mockito.when(referralManagementService.search(ArgumentMatchers.any(ReferralSearchRequest.class), + ArgumentMatchers.any(Integer.class), + ArgumentMatchers.any(Integer.class), + ArgumentMatchers.any(String.class), + ArgumentMatchers.any(Long.class), + ArgumentMatchers.any(Boolean.class))).thenThrow(new CustomException("NO_RESULT_FOUND", "No Referral found.")); + + + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(referralSearchRequest))) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ErrorRes response = objectMapper.readValue(responseStr, + ErrorRes.class); + + Assertions.assertEquals(response.getErrors().size(), 1); + } + +} diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java new file mode 100644 index 00000000000..b3413b77311 --- /dev/null +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java @@ -0,0 +1,213 @@ +package org.egov.referralmanagement.web.controllers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkResponse; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectResponse; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; +import org.egov.common.producer.Producer; +import org.egov.referralmanagement.TestConfiguration; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.helper.SideEffectRequestTestBuilder; +import org.egov.referralmanagement.helper.SideEffectTestBuilder; +import org.egov.referralmanagement.service.SideEffectService; +import org.egov.tracer.model.CustomException; +import org.egov.tracer.model.ErrorRes; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +@WebMvcTest(SideEffectApiController.class) +@Import(TestConfiguration.class) +public class SideEffectApiControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private SideEffectService sideEffectService; + + @MockBean + private Producer producer; + + @MockBean + ReferralManagementConfiguration referralManagementConfiguration; + + @Test + @DisplayName("should create side effect and return with 202 accepted") + void shouldCreateSideEffectAndReturnWith202Accepted() throws Exception { + SideEffectRequest request = SideEffectRequestTestBuilder.builder() + .withOneSideEffect() + .withApiOperationNotUpdate() + .build(); + List sideEffects = getSideEffects(); + Mockito.when(sideEffectService.create(ArgumentMatchers.any(SideEffectRequest.class))).thenReturn(sideEffects.get(0)); + + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side-effect/v1/_create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(MockMvcResultMatchers.status().isAccepted()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + SideEffectResponse response = objectMapper.readValue(responseStr, SideEffectResponse.class); + + Assertions.assertNotNull(response.getSideEffect()); + Assertions.assertNotNull(response.getSideEffect().getId()); + Assertions.assertEquals("successful", response.getResponseInfo().getStatus()); + } + + private List getSideEffects() { + SideEffect sideEffect = SideEffectTestBuilder.builder().withId().build(); + List sideEffects = new ArrayList<>(); + sideEffects.add(sideEffect); + return sideEffects; + } + + + @Test + @DisplayName("should send error response with error details with 400 bad request for create") + void shouldSendErrorResWithErrorDetailsWith400BadRequestForCreate() throws Exception { + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side-effect/v1/_create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(SideEffectRequestTestBuilder.builder() + .withOneSideEffect() + .withBadTenantIdInOneSideEffect() + .build()))) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ErrorRes response = objectMapper.readValue(responseStr, ErrorRes.class); + + Assertions.assertEquals(1, response.getErrors().size()); + Assertions.assertTrue(response.getErrors().get(0).getCode().contains("tenantId")); + } + + @Test + @DisplayName("should update side effect and return with 202 accepted") + void shouldUpdateSideEffectAndReturnWith202Accepted() throws Exception { + SideEffectRequest request = SideEffectRequestTestBuilder.builder() + .withOneSideEffectHavingId() + .withApiOperationNotNullAndNotCreate() + .build(); + SideEffect sideEffect = SideEffectTestBuilder.builder().withId().build(); + Mockito.when(sideEffectService.update(ArgumentMatchers.any(SideEffectRequest.class))).thenReturn(sideEffect); + + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side-effect/v1/_update") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(MockMvcResultMatchers.status().isAccepted()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + SideEffectResponse response = objectMapper.readValue(responseStr, SideEffectResponse.class); + + Assertions.assertNotNull(response.getSideEffect()); + Assertions.assertNotNull(response.getSideEffect().getId()); + Assertions.assertEquals("successful", response.getResponseInfo().getStatus()); + } + + @Test + @DisplayName("should send error response with error details with 400 bad request for update") + void shouldSendErrorResWithErrorDetailsWith400BadRequestForUpdate() throws Exception { + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side-effect/v1/_update") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(SideEffectRequestTestBuilder.builder() + .withOneSideEffectHavingId() + .withBadTenantIdInOneSideEffect() + .build()))) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ErrorRes response = objectMapper.readValue(responseStr, + ErrorRes.class); + + Assertions.assertEquals(1, response.getErrors().size()); + Assertions.assertTrue(response.getErrors().get(0).getCode().contains("tenantId")); + } + + @Test + @DisplayName("Should accept search request and return response as accepted") + void shouldAcceptSearchRequestAndReturnSideEffect() throws Exception { + + SideEffectSearchRequest sideEffectSearchRequest = SideEffectSearchRequest.builder().sideEffect( + SideEffectSearch.builder().taskId(Collections.singletonList("some-task-id")).build() + ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); + + Mockito.when(sideEffectService.search(ArgumentMatchers.any(SideEffectSearchRequest.class), + ArgumentMatchers.any(Integer.class), + ArgumentMatchers.any(Integer.class), + ArgumentMatchers.any(String.class), + ArgumentMatchers.any(Long.class), + ArgumentMatchers.any(Boolean.class))).thenReturn( + SearchResponse.builder() + .response(Arrays.asList(SideEffectTestBuilder.builder().withId().withAuditDetails().build())) + .build()); + + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post( + "/side-effect/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sideEffectSearchRequest))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + SideEffectBulkResponse response = objectMapper.readValue(responseStr, + SideEffectBulkResponse.class); + + Assertions.assertEquals(response.getSideEffects().size(), 1); + } + + @Test + @DisplayName("Should accept search request and return response as accepted") + void shouldThrowExceptionIfNoResultFound() throws Exception { + + SideEffectSearchRequest sideEffectSearchRequest = SideEffectSearchRequest.builder().sideEffect( + SideEffectSearch.builder().taskId(Collections.singletonList("some-task-id")).build() + ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); + + Mockito.when(sideEffectService.search(ArgumentMatchers.any(SideEffectSearchRequest.class), + ArgumentMatchers.any(Integer.class), + ArgumentMatchers.any(Integer.class), + ArgumentMatchers.any(String.class), + ArgumentMatchers.any(Long.class), + ArgumentMatchers.any(Boolean.class))).thenThrow(new CustomException("NO_RESULT_FOUND", "No Side Effect found.")); + + + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side-effect/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sideEffectSearchRequest))) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ErrorRes response = objectMapper.readValue(responseStr, + ErrorRes.class); + + Assertions.assertEquals(response.getErrors().size(), 1); + } + +} diff --git a/health-services/resource-estimation-service/CHANGELOG.md b/health-services/resource-estimation-service/CHANGELOG.md new file mode 100644 index 00000000000..e5ce4491284 --- /dev/null +++ b/health-services/resource-estimation-service/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog +## 1.0.0 - 2024-06-24 +#### Base Resource Estimation Service + 1. Resource Estimation Service manages file processing: validating data, calculating for files, updating plans, and integrating with campaigns. + 2. File Processing: In file processing, it processes files present in plan configuration by calculating resources. + 3. Updating Plan: It creates plans based on rows and updates those by putting them on topics that are consumed by the plan service. + 4. Integrate with Campaign Manager: After processing calculations, it also integrates resources and boundary with the Campaign Manager. + 5. Boundary and Data Validation: Validates boundaries and excel data during calculations. \ No newline at end of file diff --git a/health-services/resource-estimation-service/LOCALSETUP.md b/health-services/resource-estimation-service/LOCALSETUP.md new file mode 100644 index 00000000000..88506beb5eb --- /dev/null +++ b/health-services/resource-estimation-service/LOCALSETUP.md @@ -0,0 +1,39 @@ +# Local Setup + +To set up the Resource Estimation Service in your local system, clone the [Health Campaign Services repository](https://github.com/egovernments/health-campaign-services.git). + +## Dependencies + +- [x] Postgres DB +- [ ] Redis +- [ ] Elasticsearch +- [x] Kafka + - [x] Consumer + - [x] Producer + + +## Running Locally + +### Local setup +1. To set up the Resource Estimation Service in your local system, clone the [Health Campaign Services repository](https://github.com/egovernments/health-campaign-services.git). +2. Install GIT. + [For Windows](https://git-scm.com/download/win). + [For Linux](https://www.digitalocean.com/community/tutorials/how-to-install-git-on-ubuntu-18-04-quickstart). +2. Install JDK version 17 or above. + [For windows](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html). + [For Linux](https://javahelps.com/install-oracle-jdk-17-on-linux). +3. Install maven locally and configure environment variables. +4. Install Kafka (version 3.2.0 which is the latest version) - To install and run Kafka locally, follow the following links - + [Kafka for windows](https://dzone.com/articles/running-apache-kafka-on-windows-os) or [Kafka for Linux](https://tecadmin.net/install-apache-kafka-ubuntu/) +5. Install Postman - To install Postman, follow the following links - + [Postman for windows](https://www.postman.com/downloads/) +6. Install Kubectl - Kubectl is the tool that we use to interact with services deployed on our sandbox environment - + [kubectl for windows](https://core.digit.org/guides/operations-guide/working-with-kubernetes/installation-of-kubectl) + [kubectl for Linux](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/) +7. Install aws-iam-authenticator - [if the DIGIT development environment is in AWS](https://docs.aws.amazon.com/eks/latest/userguide/install-aws-iam-authenticator.html) +8. Install PostgreSQL v14 locally. +4. Also update DB config values as per your local system config. +5. Update all dependency service host either on any unified-env or port-forward. +6. Run spring boot main class + +> Note: After running the above steps, if you encounter a Kafka error, ensure that both Kafka and Zookeeper services are actively running. For connection errors with other microservices, verify the correctness of the URL in the external mapping of the data configuration or consider port-forwarding the problematic service for direct access. \ No newline at end of file diff --git a/health-services/resource-estimation-service/README.md b/health-services/resource-estimation-service/README.md new file mode 100644 index 00000000000..1d3816cce38 --- /dev/null +++ b/health-services/resource-estimation-service/README.md @@ -0,0 +1,61 @@ +# Resource Estimation Service Documentation + +## Overview + +The resource estimation service processes various file formats to estimate resources, generate microplans, upload result sheets, and update the HCM Admin Console. It integrates with other services like Mdms, Filestore, Project Factory, and Plan Service to ensure accurate resource estimation and campaign planning. + +## Key Features + +- **Parsing and Estimating Resources**: Processes file formats (Excel, Shapefiles, GeoJSON) to estimate necessary resources for micro planning by applying assumptions and formulas. +- **Validation**: Validates file data for proper data types and updates plan configuration status based on exceptions. +- **Generating Microplans**: Triggers the creation of microplans based on estimated resources and input data, detailing resource distribution for campaigns. +- **Uploading Results**: Uploads updated result sheets to a filestore, ensuring secure storage and accessibility. +- **Integrating with HCM Admin Console**: Updates the HCM Admin Console with estimated resources for effective campaign planning and execution. + +## Service Dependencies + +- **Mdms service** +- **Filestore service** +- **Project Factory service** +- **Plan service** + +## API Specification + +- Not Applicable (NA) + +## Sequence Diagram + +- To be provided (Placeholder) + +## Producer Details + +### Topics + +| Topic | Description | +|--------------------------------|-------------------------------------------------------------------------| +| resource-microplan-create-topic | Pushes to Plan Service for microplan creation after resource estimation. | +| resource-plan-config-update-topic | Updates a plan configuration with INVALID_DATA status in case of processing exceptions. | + +### Topics + +| Topic | Description | +|---------------------------|------------------------------------------------------------------------| +| plan-config-update-topic | Triggers resource estimation, microplan creation, and campaign manager integration. | + +## Configuration and Deployment + +- **Persister Config**: NA +- **Helm Chart**: Deployment details available [here](https://github.com/egovernments/DIGIT-DevOps/tree/unified-env/deploy-as-code/helm/charts/health-services/resource-estimation-service). + +## Environment Variables + +- Configure environment variables such as `db-host`, `db-name`, `db-url`, `domain`, and other DIGIT core platform services configurations before deployment. + +## MDMS Configuration + +- Configure MDMS data for Plan Service as per the documentation [here](https://github.com/egovernments/egov-mdms-data/tree/UNIFIED-QA/data/mz/health/hcm-microplanning). + +## Reference Documents + +- **MDMS Technical Document**: [Mdms service](https://core.digit.org/platform/core-services/mdms-master-data-management-service) + diff --git a/health-services/resource-estimation-service/pom.xml b/health-services/resource-estimation-service/pom.xml new file mode 100644 index 00000000000..c73dd06629d --- /dev/null +++ b/health-services/resource-estimation-service/pom.xml @@ -0,0 +1,169 @@ + + 4.0.0 + org.egov + resource-estimation-service + jar + file-processor-utility + 1.0.0 + + 17 + 32-SNAPSHOT + 17 + 17 + + + org.springframework.boot + spring-boot-starter-parent + 3.2.2 + + + src/main/java + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.flywaydb + flyway-core + 9.22.3 + + + org.postgresql + postgresql + 42.7.1 + + + org.springframework.boot + spring-boot-starter-test + test + + + io.swagger + swagger-core + 1.5.18 + + + io.swagger.core.v3 + swagger-annotations + 2.2.8 + + + org.geotools + gt-shapefile + ${geotools.version} + + + org.geotools + gt-geojson + ${geotools.version} + + + org.apache.poi + poi + 5.2.5 + + + org.apache.poi + poi-ooxml + 5.2.5 + + + org.springframework + spring-test + 5.3.10 + + + + + org.egov.services + tracer + 2.9.0-SNAPSHOT + + + org.egov + mdms-client + 2.9.0-SNAPSHOT + compile + + + org.projectlombok + lombok + true + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + jakarta.annotation + jakarta.annotation-api + + + com.fasterxml.jackson.core + jackson-databind + + + org.springframework + spring-web + + + + + + repo.egovernments.org + eGov ERP Releases Repository + https://nexus-repo.egovernments.org/nexus/content/repositories/releases/ + + + repo.egovernments.org.snapshots + eGov ERP Releases Repository + https://nexus-repo.egovernments.org/nexus/content/repositories/snapshots/ + + + repo.egovernments.org.public + eGov Public Repository Group + https://nexus-repo.egovernments.org/nexus/content/groups/public/ + + + repo.digit.org + eGov DIGIT Releases Repository + https://nexus-repo.digit.org/nexus/content/repositories/snapshots/ + + + apache.snapshots + Apache Development Snapshot Repository + https://repository.apache.org/snapshots/ + + + osgeo-snapshot + OSGeo Snapshot Repository + https://repo.osgeo.org/repository/snapshot/ + + true + + + false + + + + diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/Main.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/Main.java new file mode 100644 index 00000000000..bee96b9f016 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/Main.java @@ -0,0 +1,20 @@ +package org.egov.processor; + + +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; + +@Import({ TracerConfiguration.class }) +@SpringBootApplication +@ComponentScan(basePackages = { "org.egov.processor", "org.egov.processor.web.controllers" , "org.egov.processor.config"}) +public class Main { + + + public static void main(String[] args) throws Exception { + SpringApplication.run(Main.class, args); + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/Configuration.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/Configuration.java new file mode 100644 index 00000000000..12ce0667abd --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/Configuration.java @@ -0,0 +1,80 @@ +package org.egov.processor.config; + +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Import; +import org.springframework.stereotype.Component; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Component +@Data +@Import({ TracerConfiguration.class }) +@NoArgsConstructor +@AllArgsConstructor +@Setter +@Getter +public class Configuration { + + // MDMS + @Value("${egov.mdms.host}") + private String mdmsHost; + + @Value("${egov.mdms.search.endpoint}") + private String mdmsEndPoint; + + @Value("${egov.plan.config.host}") + private String planConfigHost; + + @Value("${egov.plan.config.endpoint}") + private String planConfigEndPoint; + + // Filestore + + @Value("${egov.filestore.service.host}") + private String fileStoreHost; + + @Value("${egov.filestore.endpoint}") + private String fileStoreEndpoint; + + @Value("${egov.filestore.upload.endpoint}") + private String fileStoreUploadEndpoint; + + @Value("${egov.plan.create.endpoint}") + private String planCreateEndPoint; + + @Value("${egov.project.factory.search.endpoint}") + private String campaignIntegrationSearchEndPoint; + + @Value("${egov.project.factory.update.endpoint}") + private String campaignIntegrationUpdateEndPoint; + + @Value("${egov.project.factory.host}") + private String projectFactoryHostEndPoint; + + @Value("${resource.microplan.create.topic}") + private String resourceMicroplanCreateTopic; + + @Value("${integrate.with.admin.console}") + private boolean isIntegrateWithAdminConsole; + + @Value("${resource.update.plan.config.consumer.topic}") + private String resourceUpdatePlanConfigConsumerTopic; + + @Value("${egov.boundary.service.host}") + private String egovBoundaryServiceHost; + + @Value("${egov.boundary.relationship.search.endpoint}") + private String egovBoundaryRelationshipSearchEndpoint; + + @Value("${egov.locale.service.host}") + private String egovLocaleServiceHost; + + @Value("${egov.locale.search.endpoint}") + private String egovLocaleSearchEndpoint; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/MainConfiguration.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/MainConfiguration.java new file mode 100644 index 00000000000..dbead6fe299 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/MainConfiguration.java @@ -0,0 +1,38 @@ +package org.egov.processor.config; + +import jakarta.annotation.PostConstruct; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import java.util.TimeZone; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.tracer.config.TracerConfiguration; + + +@Import({TracerConfiguration.class}) +public class MainConfiguration { + + @Value("${app.timezone}") + private String timeZone; + + @PostConstruct + public void initialize() { + TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); + } + + @Bean + public ObjectMapper objectMapper(){ + return new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).setTimeZone(TimeZone.getTimeZone(timeZone)); + } + + @Bean + @Autowired + public MappingJackson2HttpMessageConverter jacksonConverter(ObjectMapper objectMapper) { + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + converter.setObjectMapper(objectMapper); + return converter; + } +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java new file mode 100644 index 00000000000..797c9a894c3 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java @@ -0,0 +1,72 @@ +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/kafka/PlanConsumer.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/PlanConsumer.java new file mode 100644 index 00000000000..2aa31907413 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/PlanConsumer.java @@ -0,0 +1,44 @@ +package org.egov.processor.kafka; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.Collections; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import org.egov.processor.service.ResourceEstimationService; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.tracer.model.CustomException; +import org.springframework.http.HttpStatus; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class PlanConsumer { + + private ObjectMapper objectMapper; + + private ResourceEstimationService resourceEstimationService; + + public PlanConsumer(ObjectMapper objectMapper, ResourceEstimationService resourceEstimationService) { + this.objectMapper = objectMapper; + this.resourceEstimationService = resourceEstimationService; + } + + @KafkaListener(topics = { "${plan.config.consumer.kafka.save.topic}", "${plan.config.consumer.kafka.update.topic}" }) + public void listen(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + PlanConfigurationRequest planConfigurationRequest = objectMapper.convertValue(consumerRecord, PlanConfigurationRequest.class); + if (planConfigurationRequest.getPlanConfiguration().getStatus().equals(PlanConfiguration.StatusEnum.GENERATED)) { + resourceEstimationService.estimateResources(planConfigurationRequest); + log.info("Successfully estimated resources for plan."); + } + } catch (Exception exception) { + log.error("Error processing record from topic "+topic+" with exception :"+exception); + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + exception.toString()); + } + } +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/Producer.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/Producer.java new file mode 100644 index 00000000000..44eb1742816 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/Producer.java @@ -0,0 +1,20 @@ +package org.egov.processor.kafka; + +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.kafka.CustomKafkaTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +// 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/resource-estimation-service/src/main/java/org/egov/processor/repository/ServiceRequestRepository.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/repository/ServiceRequestRepository.java new file mode 100644 index 00000000000..9c19a935415 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/repository/ServiceRequestRepository.java @@ -0,0 +1,70 @@ +package org.egov.processor.repository; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.model.ServiceCallException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Repository; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import java.util.Map; + +import static org.egov.processor.config.ServiceConstants.EXTERNAL_SERVICE_EXCEPTION; +import static org.egov.processor.config.ServiceConstants.SEARCHER_SERVICE_EXCEPTION; + +@Repository +@Slf4j +public class ServiceRequestRepository { + + private ObjectMapper mapper; + + private RestTemplate restTemplate; + + + @Autowired + public ServiceRequestRepository(ObjectMapper mapper, RestTemplate restTemplate) { + this.mapper = mapper; + this.restTemplate = restTemplate; + } + + + public Object fetchResult(StringBuilder uri, Object request) { + mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + Object response = null; + try { + response = restTemplate.postForObject(uri.toString(), request, Map.class); + }catch(HttpClientErrorException e) { + log.error(SEARCHER_SERVICE_EXCEPTION, "Error occurred while fetching data: {}", e.getMessage()); + throw new ServiceCallException(e.getResponseBodyAsString()); + }catch(Exception e) { + log.error(SEARCHER_SERVICE_EXCEPTION, "Error occurred while fetching data: {}", e.getMessage()); + throw new ServiceCallException(e.getMessage()); + } + + return response; + } + + public Object fetchResultWithGET(StringBuilder uri) { + Object response = null; + try { + response = restTemplate.getForObject(uri.toString(), byte[].class); + } catch (HttpClientErrorException e) { + log.error(SEARCHER_SERVICE_EXCEPTION, "Error occurred while fetching data: {}", e.getMessage()); + throw new ServiceCallException(e.getResponseBodyAsString()); + } catch (Exception e) { + log.error(SEARCHER_SERVICE_EXCEPTION, "Error occurred while fetching data: {}", e.getMessage()); + throw new ServiceCallException(e.getMessage()); + } + return response; + } + + public ResponseEntity sendHttpRequest(String url, HttpEntity> requestEntity) { + return restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); + } +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java new file mode 100644 index 00000000000..ee005cd81c8 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java @@ -0,0 +1,735 @@ +package org.egov.processor.service; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.ss.usermodel.*; +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.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; +import org.egov.processor.web.models.campaignManager.CampaignResources; +import org.egov.processor.web.models.campaignManager.CampaignResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class ExcelParser implements FileParser { + + private ObjectMapper objectMapper; + + private ParsingUtil parsingUtil; + + private FilestoreUtil filestoreUtil; + + private CalculationUtil calculationUtil; + + private PlanUtil planUtil; + + private CampaignIntegrationUtil campaignIntegrationUtil; + + private Configuration config; + + private MdmsUtil mdmsUtil; + + private BoundaryUtil boundaryUtil; + + private LocaleUtil localeUtil; + + public ExcelParser(ObjectMapper objectMapper, ParsingUtil parsingUtil, FilestoreUtil filestoreUtil, + CalculationUtil calculationUtil, PlanUtil planUtil, CampaignIntegrationUtil campaignIntegrationUtil, + Configuration config, MdmsUtil mdmsUtil, BoundaryUtil boundaryUtil,LocaleUtil localeUtil) { + this.objectMapper = objectMapper; + this.parsingUtil = parsingUtil; + this.filestoreUtil = filestoreUtil; + this.calculationUtil = calculationUtil; + this.planUtil = planUtil; + this.campaignIntegrationUtil = campaignIntegrationUtil; + this.config = config; + this.mdmsUtil = mdmsUtil; + this.boundaryUtil = boundaryUtil; + this.localeUtil = localeUtil; + } + + /** + * Parses file data, extracts information from the file, and processes it. + * + * @param planConfigurationRequest The plan configuration request containing + * necessary information for parsing the file. + * @param fileStoreId The ID of the file in the file store. + * @param campaignResponse The response object to be updated with parsed + * data. + * @return The parsed and processed data. + */ + @Override + public Object parseFileData(PlanConfigurationRequest planConfigurationRequest, String fileStoreId, + Object campaignResponse) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + byte[] byteArray = filestoreUtil.getFile(planConfig.getTenantId(), fileStoreId); + File file = parsingUtil.convertByteArrayToFile(byteArray, ServiceConstants.FILE_EXTENSION); + if (file == null || !file.exists()) { + log.error("File not found: {} in tenant: {}", fileStoreId, planConfig.getTenantId()); + throw new CustomException("FileNotFound", + "The file with ID " + fileStoreId + " was not found in the tenant " + planConfig.getTenantId()); + } + return processExcelFile(planConfigurationRequest, file, fileStoreId, campaignResponse); + } + + /** + * Processes an Excel file, extracts data, and updates campaign details and + * resources. + * + * @param planConfigurationRequest The plan configuration request containing + * necessary information for processing the + * file. + * @param file The Excel file to be processed. + * @param fileStoreId The ID of the file in the file store. + * @param campaignResponse The response object to be updated with + * processed data. + * @return The ID of the uploaded file. + */ + private String processExcelFile(PlanConfigurationRequest planConfigurationRequest, File file, String fileStoreId, + Object campaignResponse) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + try (Workbook workbook = new XSSFWorkbook(file)) { + List campaignBoundaryList = new ArrayList<>(); + List campaignResourcesList = new ArrayList<>(); + DataFormatter dataFormatter = new DataFormatter(); + processSheets(planConfigurationRequest, fileStoreId, campaignResponse, planConfig, workbook, + campaignBoundaryList, campaignResourcesList, dataFormatter); + String uploadedFileStoreId = uploadFileAndIntegrateCampaign(planConfigurationRequest, campaignResponse, + planConfig, workbook, campaignBoundaryList, campaignResourcesList); + return uploadedFileStoreId; + } catch (FileNotFoundException e) { + log.error("File not found: {}", e.getMessage()); + throw new CustomException("FileNotFound", "The specified file was not found."); + } catch (InvalidFormatException e) { + log.error("Invalid format: {}", e.getMessage()); + throw new CustomException("InvalidFormat", "The file format is not supported."); + } catch (IOException e) { + log.error("Error processing Excel file: {}", e); + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + "Error processing Excel file"); + } + } + + /** + * Uploads a converted file and integrates campaign details if configured to do so. + * + * @param planConfigurationRequest The request containing configuration details including tenant ID. + * @param campaignResponse The response object containing campaign details. + * @param planConfig The configuration details specific to the plan. + * @param workbook The workbook containing data to be uploaded and integrated. + * @param campaignBoundaryList List of boundary objects related to the campaign. + * @param campaignResourcesList List of campaign resources to be integrated. + * @return The ID of the uploaded file in the file store. + */ + private String uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfigurationRequest, + Object campaignResponse, PlanConfiguration planConfig, Workbook workbook, + List campaignBoundaryList, List campaignResourcesList) { + File fileToUpload = null; + try { + fileToUpload = convertWorkbookToXls(workbook); + String uploadedFileStoreId = uploadConvertedFile(fileToUpload, planConfig.getTenantId()); + + if (config.isIntegrateWithAdminConsole()) { + campaignIntegrationUtil.updateCampaignResources(uploadedFileStoreId, campaignResourcesList, + fileToUpload.getName()); + + campaignIntegrationUtil.updateCampaignDetails(planConfigurationRequest, campaignResponse, + campaignBoundaryList, campaignResourcesList); + } + return uploadedFileStoreId; + } finally { + try { + if (fileToUpload != null && !fileToUpload.delete()) { + log.warn("Failed to delete temporary file: " + fileToUpload.getPath()); + } + }catch(SecurityException e) { + log.error("Security exception when attempting to delete file: " + e.getMessage()); + } + } + } + + /** + * Processes each sheet in the workbook for plan configuration data. + * Validates column names, processes rows, and integrates campaign details. + * + * @param planConfigurationRequest The request containing configuration details including tenant ID. + * @param fileStoreId The ID of the uploaded file in the file store. + * @param campaignResponse The response object containing campaign details. + * @param planConfig The configuration details specific to the plan. + * @param 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); + + 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); + } + }); + } + + /** + * Processes rows of data in an Excel sheet, performs calculations, updates + * campaign boundaries, and creates plans. + * + * @param planConfigurationRequest The plan configuration request containing + * necessary information for processing the + * rows. + * @param sheet The Excel sheet containing the data to be + * processed. + * @param dataFormatter The data formatter for formatting cell + * values. + * @param fileStoreId The ID of the file in the file store. + * @param campaignBoundaryList The list of campaign boundaries to be + * updated. + * @param attributeNameVsDataTypeMap Mapping of attribute names to their data types. + * @param boundaryCodeList List of boundary codes. + * @throws IOException If an I/O error occurs. + */ + private void processRows(PlanConfigurationRequest planConfigurationRequest, Sheet sheet, DataFormatter dataFormatter, String fileStoreId, List campaignBoundaryList, Map attributeNameVsDataTypeMap, List boundaryCodeList) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + Row firstRow = null; + performRowLevelCalculations(planConfigurationRequest, sheet, dataFormatter, fileStoreId, campaignBoundaryList, planConfig, attributeNameVsDataTypeMap, boundaryCodeList, firstRow); + } + + /** + * Retrieves a list of boundary codes based on the given plan configuration, campaign details, and request information. + * + * @param planConfigurationRequest The request containing configuration details including tenant ID. + * @param campaign The campaign response object containing campaign details. + * @param planConfig The configuration details specific to the plan. + * @return A list of boundary codes corresponding to the specified hierarchy type and tenant ID. + */ + private List getBoundaryCodeList(PlanConfigurationRequest planConfigurationRequest, + CampaignResponse campaign, PlanConfiguration planConfig) { + BoundarySearchResponse boundarySearchResponse = boundaryUtil.search(planConfig.getTenantId(), + campaign.getCampaign().get(0).getHierarchyType(), planConfigurationRequest); + List boundaryList = new ArrayList<>(); + List boundaryCodeList = getAllBoundaryPresentforHierarchyType( + boundarySearchResponse.getTenantBoundary().get(0).getBoundary(), boundaryList); + return boundaryCodeList; + } + + /** + * Prepares a mapping of attribute names to their corresponding indices or data types based on configuration and MDMS data. + * + * @param planConfigurationRequest The request containing configuration details including tenant ID. + * @param fileStoreId The ID of the uploaded file in the file store. + * @param campaign The campaign response object containing campaign details. + * @param planConfig The configuration details specific to the plan. + * @return A map of attribute names to their corresponding indices or data types. + */ + private Map prepareAttributeVsIndexMap(PlanConfigurationRequest planConfigurationRequest, + String fileStoreId, CampaignResponse campaign, PlanConfiguration planConfig) { + Object mdmsData = mdmsUtil.fetchMdmsData(planConfigurationRequest.getRequestInfo(), + planConfigurationRequest.getPlanConfiguration().getTenantId()); + org.egov.processor.web.models.File file = planConfig.getFiles().stream() + .filter(f -> f.getFilestoreId().equalsIgnoreCase(fileStoreId)).findFirst().get(); + Map attributeNameVsDataTypeMap = mdmsUtil.filterMasterData(mdmsData.toString(), file.getInputFileType(), + file.getTemplateIdentifier(), campaign.getCampaign().get(0).getProjectType()); + return attributeNameVsDataTypeMap; + } + + + /** + * Parses an object representing campaign response into a CampaignResponse object. + * + * @param campaignResponse The object representing campaign response to be parsed. + * @return CampaignResponse object parsed from the campaignResponse. + */ + private CampaignResponse parseCampaignResponse(Object campaignResponse) { + CampaignResponse campaign = null; + campaign = objectMapper.convertValue(campaignResponse, CampaignResponse.class); + return campaign; + } + + /** + * Performs row-level calculations and processing on each row in the sheet. + * Validates rows, maps resource values, converts assumptions, creates feature nodes, + * calculates operations results, updates campaign boundaries, and creates plan entities. + * + * @param planConfigurationRequest The request containing configuration details including tenant ID. + * @param sheet The sheet from which rows are processed. + * @param dataFormatter The data formatter for formatting cell values. + * @param fileStoreId The ID of the uploaded file in the file store. + * @param campaignBoundaryList List of boundary objects related to the campaign. + * @param planConfig The configuration details specific to the plan. + * @param attributeNameVsDataTypeMap Mapping of attribute names to their data types. + * @param boundaryCodeList List of boundary codes. + * @param firstRow The first row of the sheet. + */ + private void performRowLevelCalculations(PlanConfigurationRequest planConfigurationRequest, Sheet sheet, + DataFormatter dataFormatter, String fileStoreId, List campaignBoundaryList, + PlanConfiguration planConfig, Map attributeNameVsDataTypeMap, List boundaryCodeList, + Row firstRow) { + for (Row row : sheet) { + if(isRowEmpty(row)) + continue; + + if (row.getRowNum() == 0) { + firstRow = row; + continue; + } + + Map resultMap = new HashMap<>(); + Map mappedValues = planConfig.getResourceMapping().stream() + .filter(f -> f.getFilestoreId().equals(fileStoreId)) + .collect(Collectors.toMap(ResourceMapping::getMappedTo, ResourceMapping::getMappedFrom)); + Map assumptionValueMap = calculationUtil + .convertAssumptionsToMap(planConfig.getAssumptions()); + Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); + + Integer indexOfBoundaryCode = campaignIntegrationUtil.getIndexOfBoundaryCode(0, + campaignIntegrationUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); + validateRows(indexOfBoundaryCode, row, firstRow, attributeNameVsDataTypeMap, mappedValues, mapOfColumnNameAndIndex, + planConfigurationRequest, boundaryCodeList, sheet); + JsonNode feature = createFeatureNodeFromRow(row, dataFormatter, mapOfColumnNameAndIndex); + performCalculationsOnOperations(sheet, planConfig, row, resultMap, mappedValues, + assumptionValueMap, feature); + if (config.isIntegrateWithAdminConsole()) + campaignIntegrationUtil.updateCampaignBoundary(planConfig, feature, assumptionValueMap, mappedValues, + mapOfColumnNameAndIndex, campaignBoundaryList, resultMap); + planUtil.create(planConfigurationRequest, feature, resultMap, mappedValues); + // TODO: remove after testing + printRow(sheet, row); + } + } + + /** + * 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. + * + * @param sheet The sheet where calculations are performed. + * @param planConfig The configuration details for the plan. + * @param row The row in the sheet where calculations are applied. + * @param resultMap The map to store calculation results. + * @param mappedValues Mapping of values needed for calculations. + * @param assumptionValueMap Map of assumption values used in calculations. + * @param feature JSON node containing additional features or data for calculations. + */ + private void performCalculationsOnOperations(Sheet sheet, PlanConfiguration planConfig, Row row, + Map resultMap, Map mappedValues, + Map assumptionValueMap, JsonNode feature) { + int columnIndex = row.getLastCellNum(); // Get the index of the last cell in the row + + for (Operation operation : planConfig.getOperations()) { + BigDecimal result = calculationUtil.calculateResult(operation, feature, mappedValues, + assumptionValueMap, resultMap); + String output = operation.getOutput(); + resultMap.put(output, result); + + Cell cell = row.createCell(columnIndex++); + cell.setCellValue(result.doubleValue()); + + if (row.getRowNum() == 1) { + Cell headerCell = sheet.getRow(0).createCell(row.getLastCellNum() - 1); + headerCell.setCellValue(output); + } + } + + } + + /** + * Uploads the converted XLS file to the file store. + * + * @param convertedFile The converted XLS file to upload. + * @param tenantId The tenant ID for the file upload. + * @return The file store ID of the uploaded file, or null if an error occurred. + */ + private String uploadConvertedFile(File convertedFile, String tenantId) { + if (convertedFile != null) { + return filestoreUtil.uploadFile(convertedFile, tenantId); + } + return null; + } + + /** + * Creates a temporary file with the specified prefix and suffix. + * + * @param prefix The prefix for the temporary file. + * @param suffix The suffix for the temporary file. + * @return The created temporary file. + * @throws IOException If an IO error occurs while creating the file. + */ + private File createTempFile(String prefix, String suffix) throws IOException { + return File.createTempFile(prefix, suffix); + } + + /** + * Converts the provided workbook to XLS format. + * + * @param workbook The workbook to convert. + * @return The converted XLS file, or null if an error occurred. + */ + private File convertWorkbookToXls(Workbook workbook) { + try { + // Create a temporary file for the output XLS file + File outputFile = File.createTempFile("output", ".xls"); + + // Write the XLS file + try (FileOutputStream fos = new FileOutputStream(outputFile)) { + workbook.write(fos); + log.info("XLS file saved successfully."); + return outputFile; + } catch (IOException e) { + log.info("Error saving XLS file: " + e); + return null; + } + } catch (IOException e) { + log.info("Error converting workbook to XLS: " + e); + return null; + } + } + + /** + * Creates a JSON feature node from a row in the Excel sheet. + * + * @param row The row in the Excel sheet. + * @param dataFormatter The data formatter for formatting cell values. + * @param columnIndexMap The mapping of column names to column indices. + * @return The JSON feature node representing the row. + */ + private JsonNode createFeatureNodeFromRow(Row row, DataFormatter dataFormatter, + Map columnIndexMap) { + ObjectNode featureNode = objectMapper.createObjectNode(); + ObjectNode propertiesNode = featureNode.putObject("properties"); + + // Iterate over each entry in the columnIndexMap + for (Map.Entry entry : columnIndexMap.entrySet()) { + String columnName = entry.getKey(); + Integer columnIndex = entry.getValue(); + + // Get the cell value from the row based on the columnIndex + Cell cell = row.getCell(columnIndex); + String cellValue = dataFormatter.formatCellValue(cell); + + // Add the columnName and cellValue to the propertiesNode + propertiesNode.put(columnName, cellValue); + } +// System.out.println("Feature Node ---- > " + featureNode); + return featureNode; + } + + public void printRow(Sheet sheet, Row row) { + System.out.print("Row -> "); + for (Cell cell : row) { + int columnIndex = cell.getColumnIndex(); + // String columnName = sheet.getRow(0).getCell(columnIndex).toString(); + // System.out.print("Column " + columnName + " - "); + switch (cell.getCellType()) { + case STRING: + System.out.print(cell.getStringCellValue() + "\t"); + break; + case NUMERIC: + if (DateUtil.isCellDateFormatted(cell)) { + System.out.print(cell.getDateCellValue() + "\t"); + } else { + System.out.print(cell.getNumericCellValue() + "\t"); + } + break; + case BOOLEAN: + System.out.print(cell.getBooleanCellValue() + "\t"); + break; + case FORMULA: + System.out.print(cell.getCellFormula() + "\t"); + break; + case BLANK: + System.out.print("\t"); + break; + default: + System.out.print("\t"); + break; + } + } + System.out.println(); // Move to the next line after printing the row + } + + /** + * Validates the data in a row. + * + * @param indexOfBoundaryCode The index of the "BCode" column in the row. + * @param row The row containing the data to be validated. + * @param columnHeaderRow The row containing the column headers. + * @param attributeNameVsDataTypeMap Map containing data types from external + * source (MDMS). + * @param mappedValues Map containing mapped values. + * @param mapOfColumnNameAndIndex Map containing column names and their + * corresponding indices. + * @param planConfigurationRequest Object representing the plan configuration + * request. + * @throws CustomException if the input data is not valid or if a custom + * exception occurs. + */ + public void validateRows(Integer indexOfBoundaryCode, Row row, Row columnHeaderRow, Map attributeNameVsDataTypeMap, + Map mappedValues, Map mapOfColumnNameAndIndex, + PlanConfigurationRequest planConfigurationRequest, List boundaryCodeList, Sheet sheet) { + + try { + validateTillBoundaryCode(indexOfBoundaryCode, row, columnHeaderRow); + validateAttributes(attributeNameVsDataTypeMap, mappedValues, mapOfColumnNameAndIndex, row, columnHeaderRow, indexOfBoundaryCode, + boundaryCodeList); + } catch (JsonProcessingException e) { + log.info(ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1) + " at sheet - " + sheet); + planConfigurationRequest.getPlanConfiguration().setStatus(StatusEnum.INVALID_DATA); + planUtil.update(planConfigurationRequest); + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + ServiceConstants.INPUT_IS_NOT_VALID + row.getRowNum() + " at sheet - " + sheet); + } catch (CustomException customException) { + log.info(customException.toString()+ "at sheet - " + sheet.getSheetName()); + planConfigurationRequest.getPlanConfiguration().setStatus(StatusEnum.INVALID_DATA); + planUtil.update(planConfigurationRequest); + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + customException.getMessage()+ "at sheet - " + sheet.getSheetName()); + } + } + + /** + * Validates the data in columns from "BCode" column. + * + * @param attributeNameVsDataTypeMap Map containing data types from an external + * source (MDMS). + * @param mappedValues Map containing mapped values. + * @param mapOfColumnNameAndIndex Map containing column names and their + * corresponding indices. + * @param row The row containing the data to be validated. + * @param columnHeaderRow The row containing the column headers. + * @param indexOfBoundaryCode The index of the "BCode" column in the row. + * @throws JsonMappingException if there's an issue mapping JSON. + * @throws JsonProcessingException if there's an issue processing JSON. + */ + private void validateAttributes(Map attributeNameVsDataTypeMap, Map mappedValues, + Map mapOfColumnNameAndIndex, Row row, Row columnHeaderRow, Integer indexOfBoundaryCode, + List boundaryCodeList) throws JsonMappingException, JsonProcessingException { + for (int j = indexOfBoundaryCode; j < mapOfColumnNameAndIndex.size(); j++) { + Cell cell = row.getCell(j); + Cell columnName = columnHeaderRow.getCell(j); + String name = findByValue(mappedValues, columnName.getStringCellValue()); + if (attributeNameVsDataTypeMap.containsKey(name)) { + Map mapOfAttributes = (Map) attributeNameVsDataTypeMap.get(name); + boolean isRequired = (mapOfAttributes.containsKey(ServiceConstants.ATTRIBUTE_IS_REQUIRED) + ? (boolean) mapOfAttributes.get(ServiceConstants.ATTRIBUTE_IS_REQUIRED) + : false); + if (cell != null) { + switch (cell.getCellType()) { + case STRING: + String cellValue = cell.getStringCellValue(); + if (j == indexOfBoundaryCode && !boundaryCodeList.contains(cellValue)) { + log.info("Boundary Code " + cellValue + " is not present in boundary search. Code for row " + + (row.getRowNum() + 1) + " and cell/column " + columnName); + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + "Boundary Code " + cellValue + " is not present in boundary search. Code for row " + + (row.getRowNum() + 1) + " and cell/column " + columnName); + } + // "^[a-zA-Z0-9 .,()-]+$" + if (cellValue != null && !cellValue.isEmpty() + && cellValue.matches(ServiceConstants.VALIDATE_STRING_REGX)) { + continue; + } else { + log.info(ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1) + " and cell/column " + + columnName); + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + ServiceConstants.INPUT_IS_NOT_VALID + row.getRowNum() + " and cell " + columnName); + } + case NUMERIC: + String numricValue = Double.toString(cell.getNumericCellValue()); + // "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$" + if (numricValue != null && !numricValue.isEmpty() + && numricValue.matches(ServiceConstants.VALIDATE_NUMBER_REGX)) { + continue; + } else { + log.info(ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1) + " and cell/column " + + columnName); + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + ServiceConstants.INPUT_IS_NOT_VALID + row.getRowNum() + " and cell " + columnName); + } + case BOOLEAN: + Boolean booleanvalue = cell.getBooleanCellValue(); + // "^(?i)(true|false)$" + if (booleanvalue != null && !booleanvalue.toString().isEmpty() + && booleanvalue.toString().matches(ServiceConstants.VALIDATE_BOOLEAN_REGX)) { + continue; + } else { + log.info(ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1) + " and cell/column " + + columnName); + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + ServiceConstants.INPUT_IS_NOT_VALID + row.getRowNum() + " and cell " + columnName); + } + case BLANK: + if (!isRequired) { + continue; + }else { + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1) + " and cell " + + columnName); + } + default: + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1) + " and cell " + + columnName); + } + }else { + if(isRequired) { + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1) + " and cell " + + columnName); + } + } + } + } + } + + /** + * Validates the data in columns up to the specified index of the "BCode" + * column. + * + * @param indexOfBoundaryCode The index of the "BCode" column in the row. + * @param row The row containing the data to be validated. + * @param columnHeaderRow The row containing the column headers. + */ + private void validateTillBoundaryCode(Integer indexOfBoundaryCode, Row row, Row columnHeaderRow) { + for (int j = 0; j <= indexOfBoundaryCode - 1; j++) { + Cell cell = row.getCell(j); + if (cell != null && !cell.getCellType().name().equals("BLANK")) { + String cellValue = cell.getStringCellValue(); + if (!cellValue.isBlank()) { + if (cellValue != null && !cellValue.isEmpty() + && cellValue.matches(ServiceConstants.VALIDATE_STRING_REGX)) { + continue; + } else { + log.info(ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1) + + " and cell/column number " + (j + 1)); + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + ServiceConstants.INPUT_IS_NOT_VALID + row.getRowNum() + " and cell " + + columnHeaderRow.getCell(j)); + } + } + } + } + } + + /** + * Finds the key associated with a given value in a map. + * + * @param map The map to search. + * @param value The value to search for. + * @return The key associated with the specified value, or {@code null} if not + * found. + */ + public String findByValue(Map map, String value) { + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().equals(value)) { + return entry.getKey(); + } + } + return null; + } + + public List getAllBoundaryPresentforHierarchyType(List boundaries, + List boundaryList) { + for (EnrichedBoundary boundary : boundaries) { + boundaryList.add(boundary.getCode()); + // Recursively check children if they exist + if (boundary.getChildren() != null && !boundary.getChildren().isEmpty()) { + getAllBoundaryPresentforHierarchyType(boundary.getChildren(), boundaryList); + } + } + return boundaryList; + } + + /** + * Checks if a sheet is allowed to be processed based on MDMS constants and locale-specific configuration. + * + * @param planConfigurationRequest The request containing configuration details including request info and tenant ID. + * @param sheetName The name of the sheet to be processed. + * @return true if the sheet is allowed to be processed, false otherwise. + * @throws JsonMappingException If there's an issue mapping JSON response to Java objects. + * @throws JsonProcessingException If there's an issue processing JSON during conversion. + */ + private boolean isSheetAlloedToProcess(PlanConfigurationRequest planConfigurationRequest, String sheetName,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 (sheetName.equals(locale.getMessage())) + return false; + } + } + return true; + + } +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/FileParser.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/FileParser.java new file mode 100644 index 00000000000..b62f2a3d058 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/FileParser.java @@ -0,0 +1,13 @@ +package org.egov.processor.service; + + +import java.math.BigDecimal; +import org.egov.processor.web.models.Plan; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationRequest; + +public interface FileParser { + + Object parseFileData(PlanConfigurationRequest planConfigurationRequest , String fileStoreId, Object campaignResponse); + + } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/GeoJsonParser.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/GeoJsonParser.java new file mode 100644 index 00000000000..cdc70900a3e --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/GeoJsonParser.java @@ -0,0 +1,78 @@ +package org.egov.processor.service; + + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.File; +import java.math.BigDecimal; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.egov.processor.util.CalculationUtil; +import org.egov.processor.util.FilestoreUtil; +import org.egov.processor.util.ParsingUtil; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.ResourceMapping; + +import org.springframework.stereotype.Service; + + +@Service +@Slf4j +public class GeoJsonParser implements FileParser { + + private ObjectMapper objectMapper; + + private ParsingUtil parsingUtil; + + private FilestoreUtil filestoreUtil; + + private CalculationUtil calculationUtil; + + public GeoJsonParser(ObjectMapper objectMapper, ParsingUtil parsingUtil, FilestoreUtil filestoreUtil, CalculationUtil calculationUtil) { + this.objectMapper = objectMapper; + this.parsingUtil = parsingUtil; + this.filestoreUtil = filestoreUtil; + this.calculationUtil = calculationUtil; + } + + /** + * Parses the file data based on the provided plan configuration and file store ID. + * Converts the byte array data to a GeoJSON string, then to a JSON node. + * Calculates resources based on the operations defined in the plan configuration. + * Writes the updated JSON node to a file and uploads it to the file store. + * + * @param planConfigurationRequest The plan configuration containing mapping and operation details. + * @param fileStoreId The file store ID of the GeoJSON file to be parsed. + * @return The file store ID of the uploaded updated file, or null if an error occurred. + */ + @Override + public Object parseFileData(PlanConfigurationRequest planConfigurationRequest, String fileStoreId, Object campaignResponse) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + String geoJSON = parsingUtil.convertByteArrayToString(planConfig, fileStoreId); + + JsonNode jsonNode = parsingUtil.parseJson(geoJSON, objectMapper); + + List columnNamesList = parsingUtil.fetchAttributeNamesFromJson(jsonNode); + parsingUtil.validateColumnNames(columnNamesList, planConfig, fileStoreId); + + Map resultMap = new HashMap<>(); + Map mappedValues = planConfig.getResourceMapping().stream() + .filter(f-> f.getFilestoreId().equals(fileStoreId)) + .collect(Collectors.toMap(ResourceMapping::getMappedTo, ResourceMapping::getMappedFrom)); + Map assumptionValueMap = calculationUtil.convertAssumptionsToMap(planConfig.getAssumptions()); + + calculationUtil.calculateResources(jsonNode, planConfigurationRequest, resultMap, mappedValues, assumptionValueMap); + + File outputFile = parsingUtil.writeToFile(jsonNode, objectMapper); + + return filestoreUtil.uploadFile(outputFile, planConfig.getTenantId()); + + } + +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ResourceEstimationService.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ResourceEstimationService.java new file mode 100644 index 00000000000..c1b1ab07b7a --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ResourceEstimationService.java @@ -0,0 +1,112 @@ +package org.egov.processor.service; + + +import java.util.HashMap; +import java.util.Map; + +import org.egov.processor.config.Configuration; +import org.egov.processor.config.ServiceConstants; +import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.processor.util.CampaignIntegrationUtil; +import org.egov.processor.web.models.File; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.campaignManager.CampaignSearchRequest; +import org.springframework.stereotype.Service; + +import lombok.extern.slf4j.Slf4j; + +@Service +@Slf4j +public class ResourceEstimationService { + + private final FileParser excelParser; + private final FileParser geoJsonParser; + private final FileParser shapeFileParser; + private CampaignIntegrationUtil campaignIntegrationUtil; + private ServiceRequestRepository serviceRequestRepository; + private Configuration config; + + public ResourceEstimationService(FileParser excelParser, FileParser geoJsonParser, FileParser shapeFileParser,CampaignIntegrationUtil campaignIntegrationUtil + ,ServiceRequestRepository serviceRequestRepository, + Configuration config) { + this.excelParser = excelParser; + this.geoJsonParser = geoJsonParser; + this.shapeFileParser = shapeFileParser; + this.campaignIntegrationUtil= campaignIntegrationUtil; + this.serviceRequestRepository=serviceRequestRepository; + this.config=config; + } + + /** + * Estimates resources required for the plan configuration by parsing files and fetching campaign search results. + * + * @param planConfigurationRequest The plan configuration request containing necessary information for estimating resources. + */ + public void estimateResources(PlanConfigurationRequest planConfigurationRequest) { + PlanConfiguration planConfiguration = planConfigurationRequest.getPlanConfiguration(); + + Map parserMap = getInputFileTypeMap(); + Object campaignSearchResponse = performCampaignSearch(planConfigurationRequest); + processFiles(planConfigurationRequest, planConfiguration, parserMap, campaignSearchResponse); + } + + /** + * Performs a campaign search based on the provided plan configuration request. + * This method builds a campaign search request using the integration utility, + * fetches the search result from the service request repository, and returns it. + * + * @param planConfigurationRequest The request object containing configuration details for the campaign search. + * @return The response object containing the result of the campaign search. + */ + private Object performCampaignSearch(PlanConfigurationRequest planConfigurationRequest) { + CampaignSearchRequest campaignRequest = campaignIntegrationUtil.buildCampaignRequestForSearch(planConfigurationRequest); + Object campaignSearchResponse = serviceRequestRepository.fetchResult(new StringBuilder(config.getProjectFactoryHostEndPoint()+config.getCampaignIntegrationSearchEndPoint()), + campaignRequest); + return campaignSearchResponse; + } + + /** + * Processes files in the plan configuration by parsing active files and skipping inactive ones. + * Uses the provided parser map to parse supported file types. If a file type is not supported, + * throws an IllegalArgumentException. Skips files with a specific template identifier defined + * in ServiceConstants. + * + * @param planConfigurationRequest The request object containing configuration details. + * @param planConfiguration The plan configuration object containing files to process. + * @param parserMap A map of supported file types to their respective parsers. + * @param campaignSearchResponse The response object from a campaign search operation. + */ + private void processFiles(PlanConfigurationRequest planConfigurationRequest, PlanConfiguration planConfiguration, + Map parserMap, Object campaignSearchResponse) { + for (File file : planConfiguration.getFiles()) { + if (!file.getActive()) { + continue; + } + File.InputFileTypeEnum fileType = file.getInputFileType(); + FileParser parser = parserMap.computeIfAbsent(fileType, ft -> { + throw new IllegalArgumentException("Unsupported file type: " + ft); + }); + if (!ServiceConstants.FILE_TEMPLATE.equalsIgnoreCase(file.getTemplateIdentifier())) { + parser.parseFileData(planConfigurationRequest, file.getFilestoreId(), campaignSearchResponse); + } + } + + } + + /** + * Retrieves a map of input file types to their respective parsers. + * + * @return A map containing input file types as keys and their corresponding parsers as values. + */ + public Map getInputFileTypeMap() + { + Map parserMap = new HashMap<>(); + parserMap.put(File.InputFileTypeEnum.EXCEL, excelParser); + parserMap.put(File.InputFileTypeEnum.SHAPEFILE, shapeFileParser); + parserMap.put(File.InputFileTypeEnum.GEOJSON, geoJsonParser); + + return parserMap; + } +} + diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ShapeFileParser.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ShapeFileParser.java new file mode 100644 index 00000000000..92260690fa6 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ShapeFileParser.java @@ -0,0 +1,146 @@ +package org.egov.processor.service; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.processor.util.CalculationUtil; +import org.egov.processor.util.FilestoreUtil; +import org.egov.processor.util.ParsingUtil; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.ResourceMapping; +import org.egov.tracer.model.CustomException; +import org.geotools.api.data.DataStore; +import org.geotools.api.data.DataStoreFinder; +import org.geotools.api.data.SimpleFeatureSource; +import org.geotools.geojson.feature.FeatureJSON; +import org.springframework.stereotype.Service; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class ShapeFileParser implements FileParser { + + private ParsingUtil parsingUtil; + + private FilestoreUtil filestoreUtil; + + private CalculationUtil calculationUtil; + + private ObjectMapper objectMapper; + + public ShapeFileParser(ParsingUtil parsingUtil, FilestoreUtil filestoreUtil, CalculationUtil calculationUtil, ObjectMapper objectMapper) { + this.parsingUtil = parsingUtil; + this.filestoreUtil = filestoreUtil; + this.calculationUtil = calculationUtil; + this.objectMapper = objectMapper; + } + + /** + * Parses the file data based on the provided plan configuration and file store ID. + * Converts a Shapefile to GeoJSON format, calculates resources based on the operations + * defined in the plan configuration, and uploads the updated GeoJSON file to the file store. + * + * @param planConfigurationRequest The plan configuration containing mapping and operation details. + * @param fileStoreId The file store ID of the Shapefile to be converted and parsed. + * @return The file store ID of the uploaded updated file, or null if an error occurred. + */ + @Override + public Object parseFileData(PlanConfigurationRequest planConfigurationRequest, String fileStoreId, Object campaignResponse) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + File geojsonFile = convertShapefileToGeoJson(planConfig, fileStoreId); + String geoJSONString = parsingUtil.convertFileToJsonString(geojsonFile); + JsonNode jsonNode = parsingUtil.parseJson(geoJSONString, objectMapper); + + List columnNamesList = parsingUtil.fetchAttributeNamesFromJson(jsonNode); + parsingUtil.validateColumnNames(columnNamesList, planConfig, fileStoreId); + + Map resultMap = new HashMap<>(); + Map mappedValues = planConfig.getResourceMapping().stream() + .filter(f-> f.getFilestoreId().equals(fileStoreId)) + .collect(Collectors.toMap(ResourceMapping::getMappedTo, ResourceMapping::getMappedFrom)); + Map assumptionValueMap = calculationUtil.convertAssumptionsToMap(planConfig.getAssumptions()); + + calculationUtil.calculateResources(jsonNode, planConfigurationRequest, resultMap, mappedValues, assumptionValueMap); + + File updatedGeojsonFile = parsingUtil.writeToFile(jsonNode, objectMapper); + + return filestoreUtil.uploadFile(updatedGeojsonFile, planConfig.getTenantId()); + } + + /** + * Converts a Shapefile to GeoJSON format and writes it to a GeoJSON file. + * + * @param planConfig The plan configuration containing mapping details. + * @param fileStoreId The file store ID of the Shapefile to be converted. + * @return The GeoJSON file containing the converted data. + */ + public File convertShapefileToGeoJson(PlanConfiguration planConfig, String fileStoreId) { + File shapefile = null; + try { + shapefile = parsingUtil.extractShapeFilesFromZip(planConfig, fileStoreId, "shapefile"); + } catch (IOException exception) { + log.error(exception.getMessage()); + } + + File geojsonFile = new File("geojsonfile.geojson"); + + SimpleFeatureSource featureSource = null; + DataStore dataStore; + try { + dataStore = getDataStore(shapefile); + String typeName = dataStore.getTypeNames()[0]; + featureSource = dataStore.getFeatureSource(typeName); + + writeFeaturesToGeoJson(featureSource, geojsonFile); + } catch (IOException e) { + throw new CustomException("ERROR_IN_SHAPE_FILE_PARSER_WHILE_CONVERTING_SHAPE_FILE_TO_GEOJSON_IN_METHOD_CONVERTSHAPEFILETOGEOJSON",e.getMessage()); + } + + return geojsonFile; + } + + /** + * Retrieves a DataStore object for a given Shapefile. + * + * @param shapefile The Shapefile to retrieve the DataStore for. + * @return The DataStore object for the Shapefile. + * @throws IOException If an I/O error occurs. + */ + private DataStore getDataStore(File shapefile) { + Map params = new HashMap<>(); + try { + params.put("url", shapefile.toURI().toURL()); + return DataStoreFinder.getDataStore(params); + } catch (IOException e) { + throw new CustomException("Exception accours while getting data store",e.getMessage()); + } + + } + + /** + * Writes features from a SimpleFeatureSource to a GeoJSON file. + * + * @param featureSource The SimpleFeatureSource containing the features to write. + * @param geojsonFile The GeoJSON file to write the features to. + * @throws IOException If an I/O error occurs. + */ + private void writeFeaturesToGeoJson(SimpleFeatureSource featureSource, File geojsonFile) { + try (FileOutputStream geojsonStream = new FileOutputStream(geojsonFile)) { + new FeatureJSON().writeFeatureCollection(featureSource.getFeatures(), geojsonStream); + } catch (IOException e) { + throw new CustomException("Failed to write feature to GeoJson",e.getMessage()); + } + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/BoundaryUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/BoundaryUtil.java new file mode 100644 index 00000000000..b898dbe5110 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/BoundaryUtil.java @@ -0,0 +1,53 @@ +package org.egov.processor.util; + +import static org.egov.processor.config.ServiceConstants.HIERARCHYTYPE_REPLACER; +import static org.egov.processor.config.ServiceConstants.TENANTID_REPLACER; + +import org.egov.processor.config.Configuration; +import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.boundary.BoundarySearchResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class BoundaryUtil { + + private Configuration config; + + private ServiceRequestRepository serviceRequestRepository; + + private ObjectMapper mapper; + + public BoundaryUtil(Configuration config, ServiceRequestRepository serviceRequestRepository, ObjectMapper mapper) { + this.config = config; + this.serviceRequestRepository = serviceRequestRepository; + this.mapper = mapper; + } + + public BoundarySearchResponse search(String tenantId, String hierarchyType,PlanConfigurationRequest planConfigurationRequest) { + String boundaryRelationShipSearchLink = getBoundaryRelationShipSearchLink(tenantId, hierarchyType); + Object response; + BoundarySearchResponse searchResponse = null; + try { + response = serviceRequestRepository.fetchResult(new StringBuilder(boundaryRelationShipSearchLink),planConfigurationRequest.getRequestInfo()); + return searchResponse = mapper.convertValue(response, BoundarySearchResponse.class); + + } catch (Exception ex) { + log.error("Boundary relationship response error!!", ex); + throw new CustomException("BOUNDARY_SEARCH_EXCEPTION", "Exception occurs while searhing boundary or parsing search response of boundary relationship for tenantId: "+tenantId); + } + } + + private String getBoundaryRelationShipSearchLink(String tenantId, String hierarchyType) { + String fileStoreServiceLink = config.getEgovBoundaryServiceHost() + config.getEgovBoundaryRelationshipSearchEndpoint(); + fileStoreServiceLink = fileStoreServiceLink.replace(TENANTID_REPLACER, tenantId); + fileStoreServiceLink = fileStoreServiceLink.replace(HIERARCHYTYPE_REPLACER, hierarchyType); + return fileStoreServiceLink; + } +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CalculationUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CalculationUtil.java new file mode 100644 index 00000000000..d6b53891a8b --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CalculationUtil.java @@ -0,0 +1,139 @@ +package org.egov.processor.util; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.processor.config.ServiceConstants; +import org.egov.processor.web.models.Assumption; +import org.egov.processor.web.models.Operation; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; + +import static org.egov.processor.config.ServiceConstants.PROPERTIES; + +@Component +public class CalculationUtil { + + private PlanUtil planUtil; + + + + public CalculationUtil(PlanUtil planUtil) { + this.planUtil = planUtil; + } + + /** + * Calculates the output value based on the input value, operator, and assumption value. + * + * @param input The input value. + * @param operator The operator enum. + * @param assumptionValue The assumption value. + * @return The calculated output. + */ + public BigDecimal calculateOutputValue(BigDecimal input, Operation.OperatorEnum operator, BigDecimal assumptionValue) { + return switch (operator) { + case PLUS -> input.add(assumptionValue); + case MINUS -> input.subtract(assumptionValue); + case SLASH -> input.divide(assumptionValue,ServiceConstants.DEFAULT_SCALE,RoundingMode.DOWN).setScale(ServiceConstants.DEFAULT_SCALE); + case STAR -> input.multiply(assumptionValue); + case PERCENT -> input.remainder(assumptionValue); + case _U -> input.pow(assumptionValue.intValue()); + default -> throw new CustomException("UNSUPPORTED_OPERATOR", "Unsupported operator: " + operator); + }; + } + + /** + * Converts a list of assumptions into a map with assumption keys as keys and assumption values as values. + * + * @param assumptions The list of assumptions to convert. + * @return The map of assumptions. + */ + public Map convertAssumptionsToMap(List assumptions) { + return assumptions.stream().collect(Collectors.toMap(Assumption::getKey, Assumption::getValue)); + } + + /** + * Calculates resources based on the provided JSON node, list of operations, and assumption values. + * + * @param jsonNode The JSON node containing the data. + * @param resultMap The map to store the results. + * @param mappedValues The mapped values for inputs. + * @param assumptionValueMap The assumption values map. + */ + public void calculateResources(JsonNode jsonNode, PlanConfigurationRequest planConfigurationRequest, Map resultMap, + Map mappedValues, Map assumptionValueMap) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + for (JsonNode feature : jsonNode.get("features")) { + for (Operation operation : planConfig.getOperations()) { + BigDecimal result = calculateResult(operation, feature, mappedValues, assumptionValueMap, resultMap); + String output = operation.getOutput(); + resultMap.put(output, result); + ((ObjectNode) feature.get("properties")).put(output, result); + } + planUtil.create(planConfigurationRequest,feature,resultMap,mappedValues); + + } + } + + /** + * Retrieves the input value from the JSON node based on the input and input mapping. + * + * @param resultMap The map containing previous results. + * @param feature The JSON node feature. + * @param input The input key. + * @param columnName The input from mapping. + * @return The input value. + */ + public BigDecimal getInputValueFromJsonFeature(Map resultMap, JsonNode feature, String input, String columnName) { + if (resultMap.containsKey(input)) { + return resultMap.get(input); + } else { + if (feature.get(PROPERTIES).get(columnName) != null) { + try { + String cellValue = String.valueOf(feature.get(PROPERTIES).get(columnName)); + BigDecimal value; + // Handle scientific notation + if (cellValue.contains(ServiceConstants.SCIENTIFIC_NOTATION_INDICATOR)) { + value = new BigDecimal(cellValue); + } else { + String cleanedValue = cellValue.replaceAll("[^\\d.\\-E]", ""); + value = new BigDecimal(cleanedValue); + } + return value; + } catch (NumberFormatException | NullPointerException e) { + return BigDecimal.ZERO; + } + } else { + throw new CustomException("INPUT_VALUE_NOT_FOUND", "Input value not found: " + input); + } + } + } + + /** + * Calculates a result based on the provided operation and inputs. + * + * @param operation The operation object containing details like input, operator, and assumption value. + * @param feature The JSON node representing additional features or parameters for calculation. + * @param mappedValues A map containing mappings for input keys to their corresponding values. + * @param assumptionValueMap A map containing assumption values referenced by keys. + * @param resultMap A map to store and update the calculated results. + * @return The calculated result as a BigDecimal. + */ + public BigDecimal calculateResult(Operation operation, JsonNode feature, Map mappedValues, Map assumptionValueMap, Map resultMap) + { + String input = operation.getInput(); + String inputFromMapping = mappedValues.get(input); + BigDecimal inputValue = getInputValueFromJsonFeature(resultMap, feature, operation.getInput(), inputFromMapping); + BigDecimal assumptionValue = assumptionValueMap.get(operation.getAssumptionValue()); + return calculateOutputValue(inputValue, operation.getOperator(), assumptionValue); + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java new file mode 100644 index 00000000000..d14b3512aef --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java @@ -0,0 +1,287 @@ +package org.egov.processor.util; + +import static org.egov.processor.config.ServiceConstants.PROPERTIES; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; + +import org.apache.commons.lang.StringUtils; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.ss.usermodel.DataFormatter; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.egov.processor.config.Configuration; +import org.egov.processor.config.ServiceConstants; +import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.processor.service.ExcelParser; +import org.egov.processor.web.models.File; +import org.egov.processor.web.models.Operation; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.ResourceMapping; +import org.egov.processor.web.models.campaignManager.Boundary; +import org.egov.processor.web.models.campaignManager.CampaignDetails; +import org.egov.processor.web.models.campaignManager.CampaignRequest; +import org.egov.processor.web.models.campaignManager.CampaignResources; +import org.egov.processor.web.models.campaignManager.CampaignResponse; +import org.egov.processor.web.models.campaignManager.CampaignSearchRequest; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class CampaignIntegrationUtil { + + private ServiceRequestRepository serviceRequestRepository; + private Configuration config; + private ObjectMapper mapper; + + public CampaignIntegrationUtil(ServiceRequestRepository serviceRequestRepository, Configuration config, + ObjectMapper mapper, FilestoreUtil filestoreUtil, ParsingUtil parsingUtil) { + + this.serviceRequestRepository = serviceRequestRepository; + this.config = config; + this.mapper = mapper; + } + + /** + * Updates campaign details based on the provided plan configuration request and response data. + * This method integrates the campaign details obtained from the response into the provided plan configuration request. + * It also updates the campaign boundaries and resources accordingly. + * + * @param planConfigurationRequest The plan configuration request containing the execution plan details. + * @param response The response object containing campaign details. + * @param campaignBoundaryList The list of campaign boundaries. + * @param campaignResourcesList The list of campaign resources. + */ + public void updateCampaignDetails(PlanConfigurationRequest planConfigurationRequest,Object response,List campaignBoundaryList,List campaignResourcesList) { + CampaignResponse campaignResponse = null; + try { + campaignResponse = mapper.convertValue(response, CampaignResponse.class); + campaignResponse.getCampaign().get(0).setResources(campaignResourcesList); + Boundary[] array = campaignBoundaryList.toArray(new Boundary[0]); + campaignResponse.getCampaign().get(0).setBoundaries(campaignBoundaryList.toArray(new Boundary[0])); + serviceRequestRepository.fetchResult( + new StringBuilder(config.getProjectFactoryHostEndPoint() + config.getCampaignIntegrationUpdateEndPoint()), + buildCampaignRequestForUpdate(planConfigurationRequest, campaignResponse)); + log.info("Campaign Integration successful."); + } catch (Exception e) { + log.error(ServiceConstants.ERROR_WHILE_SEARCHING_CAMPAIGN + + planConfigurationRequest.getPlanConfiguration().getExecutionPlanId(), e); + throw new CustomException("Failed to update campaign details in CampaignIntegration class within method updateCampaignDetails.", e.toString()); + } + } + + /** + * Updates the campaign resources in the given campaign response based on the files specified in the plan configuration request. + * + * @param campaignResponse The campaign response object to be updated with resources. + * @param planConfigurationRequest The plan configuration request containing file information. + * @param fileStoreId The file store ID. + */ + public void updateResources(CampaignResponse campaignResponse, PlanConfigurationRequest planConfigurationRequest, + String fileStoreId) { + List campaignResourcesList = new ArrayList<>(); + List files = planConfigurationRequest.getPlanConfiguration().getFiles(); + for (File file : files) { + CampaignResources campaignResource = new CampaignResources(); + campaignResource.setFilename(ServiceConstants.FILE_NAME); + campaignResource.setFilestoreId(fileStoreId); + campaignResource.setType(ServiceConstants.FILE_TYPE); + campaignResourcesList.add(campaignResource); + } + campaignResponse.getCampaign().get(0).setResources(campaignResourcesList); + } + + /** + * Builds a campaign request object for updating campaign details based on the provided plan configuration request and campaign response. + * + * @param planConfigurationRequest The plan configuration request containing necessary information for updating the campaign. + * @param campaignResponse The campaign response containing the updated campaign details. + * @return The campaign request object built for updating campaign details. + */ + private CampaignRequest buildCampaignRequestForUpdate(PlanConfigurationRequest planConfigurationRequest, + CampaignResponse campaignResponse) { + return CampaignRequest.builder().requestInfo(planConfigurationRequest.getRequestInfo()) + .campaignDetails(campaignResponse.getCampaign().get(0)).build(); + + } + + /** + * Updates campaign boundary based on the provided plan configuration, feature, assumption values, mapped values, column index map, boundary list, and result map. + * + * @param planConfig The plan configuration containing relevant details. + * @param feature The JSON node representing the feature. + * @param assumptionValueMap The map containing assumption values. + * @param mappedValues The map containing mapped values. + * @param mapOfColumnNameAndIndex The map containing column names and their indices. + * @param boundaryList The list of campaign boundaries to update. + * @param resultMap The map containing result values. + * @throws IOException If an I/O error occurs. + */ + public void updateCampaignBoundary(PlanConfiguration planConfig, JsonNode feature, + Map assumptionValueMap, Map mappedValues, + Map mapOfColumnNameAndIndex, List boundaryList, + Map resultMap) { + Integer indexOfType = null; + boolean validToAdd = false; + Integer indexValue = 0; + Boundary boundary = new Boundary(); + List> sortedColumnList = sortColumnByIndex(mapOfColumnNameAndIndex); + indexValue = getIndexOfBoundaryCode(indexValue, sortedColumnList, mappedValues); + prepareBoundary(indexOfType, indexValue, sortedColumnList, feature, boundary, mappedValues); + if (isValidToAdd(boundaryList, resultMap, validToAdd, boundary)) + boundaryList.add(boundary); + } + + /** + * Retrieves the index value of the boundary code from the sorted column list based on the mapped values. + * + * @param indexValue The initial index value. + * @param sortedColumnList The sorted list of column names and indices. + * @param mappedValues The map containing mapped values. + * @return The index value of the boundary code. + */ + public Integer getIndexOfBoundaryCode(Integer indexValue, List> sortedColumnList,Map mappedValues) { + for (Map.Entry entry : sortedColumnList) { + if (entry.getKey().equals(mappedValues.get(ServiceConstants.BOUNDARY_CODE))) { + indexValue = entry.getValue(); + } + } + return indexValue; + } + + /** + * Prepares a campaign boundary based on the provided index values, sorted column list, feature, and mapped values. + * + * @param indexOfType The index of the boundary type. + * @param indexValue The index value. + * @param sortedColumnList The sorted list of column names and indices. + * @param feature The JSON node representing the feature. + * @param boundary The boundary object to be prepared. + * @param mappedValues The map containing mapped values. + * @return The index of the boundary type after preparation. + */ + private Integer prepareBoundary(Integer indexOfType, Integer indexValue, + List> sortedColumnList, JsonNode feature, Boundary boundary,Map mappedValues) { + String codeValue = getBoundaryCodeValue(ServiceConstants.BOUNDARY_CODE, feature, mappedValues); + boundary.setCode(codeValue); + for (int j = 0; j < indexValue; j++) { + Map.Entry entry = sortedColumnList.get(j); + String value = String.valueOf(feature.get(PROPERTIES).get(entry.getKey())); + if (StringUtils.isNotBlank(value) && value.length() > 2) { + boundary.setType(entry.getKey()); + indexOfType = entry.getValue(); + } + } + if (indexOfType == 0) { + boundary.setRoot(true); + boundary.setIncludeAllChildren(true); + } + return indexOfType; + } + + /** + * Checks if the provided boundary is valid to add to the boundary list based on the result map. + * + * @param boundaryList The list of existing boundaries. + * @param resultMap The map containing result values. + * @param validToAdd The flag indicating whether the boundary is valid to add. + * @param boundary The boundary to be checked for validity. + * @return True if the boundary is valid to add, false otherwise. + */ + private boolean isValidToAdd(List boundaryList, Map resultMap, boolean validToAdd, + Boundary boundary) { + for (Entry entry : resultMap.entrySet()) { + if (entry.getValue().compareTo(new BigDecimal(0)) > 0) { + validToAdd = true; + } else { + validToAdd = false; + break; + } + } + return validToAdd; + } + + /** + * Sorts the column names and indices based on the provided map of column names and indices. + * + * @param mapOfColumnNameAndIndex The map containing column names and their corresponding indices. + * @return The sorted list of column names and indices. + */ + public List> sortColumnByIndex(Map mapOfColumnNameAndIndex) { + List> sortedColumnList = new ArrayList<>(mapOfColumnNameAndIndex.entrySet()); + Collections.sort(sortedColumnList, new Comparator>() { + @Override + public int compare(Map.Entry o1, Map.Entry o2) { + return o1.getValue().compareTo(o2.getValue()); + } + }); + return sortedColumnList; + } + + /** + * Retrieves the value of the boundary code from the feature JSON node based on the mapped values. + * + * @param input The input key. + * @param feature The JSON node representing the feature. + * @param mappedValues The map containing mapped values. + * @return The value of the boundary code. + * @throws CustomException If the input value is not found in the feature JSON node. + */ + private String getBoundaryCodeValue(String input, JsonNode feature, Map mappedValues) { + if (feature.get(PROPERTIES).get(mappedValues.get(input)) != null) { + String value = String.valueOf(feature.get(PROPERTIES).get(mappedValues.get(input))); + return ((value != null && value.length() > 2) ? value.substring(1, value.length() - 1) : value); + } else { + throw new CustomException("INPUT_VALUE_NOT_FOUND", "Input value not found: " + input); + } + } + + /** + * Updates campaign resources with the provided file store ID. + * + * @param fileStoreId The file store ID. + * @param campaignResourcesList The list of campaign resources to update. + */ + public void updateCampaignResources(String fileStoreId,List campaignResourcesList,String fileName) { + CampaignResources campaignResource = new CampaignResources(); + campaignResource.setFilename(fileName); + campaignResource.setFilestoreId(fileStoreId); + campaignResource.setType(ServiceConstants.FILE_TYPE); + campaignResourcesList.add(campaignResource); + + } + + /** + * Builds a campaign search request based on the provided plan configuration request. + * + * @param planConfigurationRequest The plan configuration request containing necessary information for building the search request. + * @return The campaign search request object built for searching campaigns. + */ + public CampaignSearchRequest buildCampaignRequestForSearch(PlanConfigurationRequest planConfigurationRequest) { + + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + List id = new ArrayList(); + id.add(planConfig.getExecutionPlanId()); + return CampaignSearchRequest.builder().requestInfo(planConfigurationRequest.getRequestInfo()) + .campaignDetails(CampaignDetails.builder().ids(id).tenantId(planConfig.getTenantId()).build()).build(); + + } +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/FilestoreUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/FilestoreUtil.java new file mode 100644 index 00000000000..37cae634df2 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/FilestoreUtil.java @@ -0,0 +1,214 @@ +package org.egov.processor.util; + +import static org.egov.processor.config.ServiceConstants.FILES; +import static org.egov.processor.config.ServiceConstants.FILESTORE_ID; +import static org.egov.processor.config.ServiceConstants.FILESTORE_ID_REPLACER; +import static org.egov.processor.config.ServiceConstants.MICROPLANNING_MODULE; +import static org.egov.processor.config.ServiceConstants.MODULE; +import static org.egov.processor.config.ServiceConstants.NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM_CODE; +import static org.egov.processor.config.ServiceConstants.NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM_MESSAGE; +import static org.egov.processor.config.ServiceConstants.TENANTID; +import static org.egov.processor.config.ServiceConstants.TENANTID_REPLACER; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.List; + +import org.egov.processor.config.Configuration; +import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.MultipartFile; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class FilestoreUtil { + + private Configuration config; + + private ServiceRequestRepository serviceRequestRepository; + + + public FilestoreUtil(Configuration config, ServiceRequestRepository serviceRequestRepository) { + this.config = config; + this.serviceRequestRepository = serviceRequestRepository; + } + + /** + * Retrieves a file from the file store service based on the tenant ID and file store ID. + * + * @param tenantId The ID of the tenant. + * @param fileStoreId The ID of the file in the file store. + * @return The file content as a byte array. + */ + public byte[] getFile(String tenantId, String fileStoreId) { + String fileStoreServiceLink = getFileStoreServiceLink(tenantId, fileStoreId); + byte[] responseInByteArray; + Object response; + try { + response = serviceRequestRepository.fetchResultWithGET(new StringBuilder(fileStoreServiceLink)); + responseInByteArray = (byte[]) response; + } catch (Exception ex) { + log.error("File store id response error!!", ex); + throw new CustomException("FILESTORE_EXCEPTION", "File Store response can not parsed!!!"); + } + return responseInByteArray; + } + + + /** + * Uploads a file to the file store service. + * + * @param file The file to upload. + * @param tenantId The ID of the tenant. + * @return The file store ID of the uploaded file. + */ + public String uploadFile(File file, String tenantId) { + byte[] fileContent = readFileContent(file); + MultipartFile multipartFile = createMultipartFile(file, fileContent); + String url = config.getFileStoreHost() + config.getFileStoreUploadEndpoint(); + HttpHeaders headers = createHttpHeaders(multipartFile.getName()); + MultiValueMap body = createHttpBody(multipartFile, tenantId); + HttpEntity> requestEntity = new HttpEntity<>(body, headers); + ResponseEntity responseEntity = serviceRequestRepository.sendHttpRequest(url, requestEntity); + return fetchFilestoreIdFromResponse(responseEntity); + } + + /** + * Generates the file store service link by combining the file store host and endpoint, + * and replacing placeholders for tenant ID and file store ID. + * + * @param tenantId The ID of the tenant. + * @param fileStoreId The ID of the file store. + * @return The generated file store service link. + */ + private String getFileStoreServiceLink(String tenantId, String fileStoreId) { + String fileStoreServiceLink = config.getFileStoreHost() + config.getFileStoreEndpoint(); + fileStoreServiceLink = fileStoreServiceLink.replace(TENANTID_REPLACER, tenantId); + fileStoreServiceLink = fileStoreServiceLink.replace(FILESTORE_ID_REPLACER, fileStoreId); + return fileStoreServiceLink; + } + + + /** + * Reads the content of a file as a byte array. + * + * @param file The file to read. + * @return The file content as a byte array. + */ + private byte[] readFileContent(File file) { + try { + return Files.readAllBytes(file.toPath()); + } catch (IOException e) { + throw new CustomException("IOException",e.getMessage()); + } + } + + /** + * Creates a multipart file from a file and its content. + * + * @param file The file to create a multipart file from. + * @param fileContent The content of the file as a byte array. + * @return The created multipart file. + */ + private MultipartFile createMultipartFile(File file, byte[] fileContent) { + List excelExtensions = Arrays.asList("xls", "xlsx"); + String fileExtension = getFileExtension(file); + MultipartFile multipartFile = null; + if (excelExtensions.contains(fileExtension)) { + multipartFile = new MockMultipartFile(file.getName(), file.getName(), "application/xls", fileContent); + } + else + multipartFile = new MockMultipartFile(file.getName(), file.getName(), "application/geo+json", fileContent); + + return multipartFile; + } + + /** + * Creates HTTP headers for the multipart file upload. + * + * @param filename The name of the file. + * @return The HTTP headers. + */ + private HttpHeaders createHttpHeaders(String filename) { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + headers.add(HttpHeaders.CONTENT_DISPOSITION, String.format("form-data; name=\"file\"; filename=\"%s\"", filename)); + headers.set("Accept", "application/json, text/plain, */*"); + return headers; + } + + /** + * Creates the HTTP body for the multipart file upload. + * + * @param multipartFile The multipart file to upload. + * @param tenantId The ID of the tenant. + * @return The HTTP body. + */ + private MultiValueMap createHttpBody(MultipartFile multipartFile, String tenantId) { + MultiValueMap body = new LinkedMultiValueMap<>(); + try { + body.add("file", new HttpEntity<>(multipartFile.getBytes(), createHttpHeaders(multipartFile.getName()))); + } catch (IOException e) { + throw new CustomException(NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM_CODE, NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM_MESSAGE); + } + body.add(TENANTID, tenantId); + body.add(MODULE, MICROPLANNING_MODULE); + return body; + } + + /** + * Extracts the file store ID from the response entity of the file store service. + * + * @param responseEntity The response entity from the file store service. + * @return The file store ID of the uploaded file. + */ + public String fetchFilestoreIdFromResponse(ResponseEntity responseEntity) { + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode rootNode; + try { + rootNode = objectMapper.readTree(responseEntity.getBody()); + } catch (JsonProcessingException e) { + log.error(e.getMessage()); + throw new CustomException("FILESTORE_EXCEPTION", "File Store response can not parsed!!!"); + } + + String fileStoreId = rootNode.get(FILES).get(0).get(FILESTORE_ID).asText(); + System.out.println("FileStoreId: " + fileStoreId); + return fileStoreId; + } + + /** + * Retrieves the file extension from a file name. + * + * @param file The file to get the extension from. + * @return The file extension. + */ + public String getFileExtension(File file) { + String fileName = file.getName(); + String extension = ""; + + int lastIndexOfDot = fileName.lastIndexOf('.'); + if (lastIndexOfDot >= 0) { + extension = fileName.substring(lastIndexOfDot + 1); + } + + return extension; + } + +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/LocaleUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/LocaleUtil.java new file mode 100644 index 00000000000..1ecb725308f --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/LocaleUtil.java @@ -0,0 +1,80 @@ +package org.egov.processor.util; + +import java.util.List; + +import org.egov.processor.config.Configuration; +import org.egov.processor.config.ServiceConstants; +import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.processor.web.models.LocaleResponse; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.boundary.BoundarySearchResponse; +import org.egov.processor.web.models.campaignManager.Boundary; +import org.egov.processor.web.models.campaignManager.CampaignResources; +import org.egov.processor.web.models.campaignManager.CampaignResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +/** + * Utility class for handling operations related to locale data retrieval and processing. + * This class encapsulates methods to search for locale information based on plan configuration requests. + * It utilizes a service request repository to interact with external services and ObjectMapper for JSON conversion. + */ +@Component +@Slf4j +public class LocaleUtil { + + private ServiceRequestRepository serviceRequestRepository; + private Configuration config; + private ObjectMapper mapper; + + /** + * Constructs a LocaleUtil instance with necessary dependencies. + * + * @param serviceRequestRepository The repository for making service requests. + * @param config Configuration settings for the application. + * @param mapper ObjectMapper for JSON serialization/deserialization. + */ + public LocaleUtil(ServiceRequestRepository serviceRequestRepository, Configuration config, ObjectMapper mapper) { + + this.serviceRequestRepository = serviceRequestRepository; + this.config = config; + this.mapper = mapper; + } + + /** + * Searches for locale information based on the provided plan configuration request. + * Retrieves locale-specific data using service request repository and converts the response + * into a LocaleResponse object. + * + * @param planConfigurationRequest The request containing configuration details including request info. + * @return LocaleResponse containing locale-specific information. + * @throws CustomException If an error occurs during the locale search process. + */ + public LocaleResponse searchLocale(PlanConfigurationRequest planConfigurationRequest) { + Object response; + String localeToUse = planConfigurationRequest.getRequestInfo().getMsgId().split("\\|")[1]; + String tenantId = planConfigurationRequest.getRequestInfo().getUserInfo().getTenantId(); + LocaleResponse localeResponse = null; + try { + + String url = config.getEgovLocaleSearchEndpoint() + .replace("{module}", ServiceConstants.MDMS_LOCALE_SEARCH_MODULE) + .replace("{locale}", localeToUse) + .replace("{tenantId}", tenantId); + response = serviceRequestRepository.fetchResult(new StringBuilder(config.getEgovLocaleServiceHost() + url), + planConfigurationRequest.getRequestInfo()); + localeResponse = mapper.convertValue(response, LocaleResponse.class); + log.info("Locale Search successful."); + return localeResponse; + } catch (Exception e) { + log.error(ServiceConstants.ERROR_WHILE_SEARCHING_LOCALE + localeToUse + " and tenantId" + tenantId, e); + throw new CustomException( + ServiceConstants.ERROR_WHILE_SEARCHING_LOCALE + localeToUse + " and tenantId" + tenantId, + e.toString()); + } + } +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/MdmsUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/MdmsUtil.java new file mode 100644 index 00000000000..229dbf57f45 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/MdmsUtil.java @@ -0,0 +1,231 @@ +package org.egov.processor.util; + +import static org.egov.processor.config.ServiceConstants.ERROR_WHILE_FETCHING_FROM_MDMS; +import static org.egov.processor.config.ServiceConstants.NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_CODE; +import static org.egov.processor.config.ServiceConstants.NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.egov.common.contract.request.RequestInfo; +import org.egov.mdms.model.MasterDetail; +import org.egov.mdms.model.MdmsCriteria; +import org.egov.mdms.model.MdmsCriteriaReq; +import org.egov.mdms.model.MdmsResponse; +import org.egov.mdms.model.ModuleDetail; +import org.egov.processor.config.Configuration; +import org.egov.processor.config.ServiceConstants; +import org.egov.processor.web.models.File; +import org.egov.tracer.model.CustomException; +import org.flywaydb.core.internal.util.JsonUtils; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; +import org.springframework.web.client.RestTemplate; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +public class MdmsUtil { + + private RestTemplate restTemplate; + + private ObjectMapper mapper; + + private Configuration configs; + + public MdmsUtil(RestTemplate restTemplate, ObjectMapper mapper, Configuration configs) { + this.restTemplate = restTemplate; + this.mapper = mapper; + this.configs = configs; + } + + /** + * Fetches MDMS (Municipal Data Management System) data using the provided + * request information and tenant ID. + * + * @param requestInfo The request information. + * @param tenantId The ID of the tenant for which MDMS data is to be fetched. + * @return The MDMS response data. + * @throws CustomException if there's an error while fetching MDMS data or if no + * data is found for the given tenant. + */ + public Object fetchMdmsData(RequestInfo requestInfo, String tenantId) { + StringBuilder uri = new StringBuilder(); + uri.append(configs.getMdmsHost()).append(configs.getMdmsEndPoint()); + MdmsCriteriaReq mdmsCriteriaReq = getMdmsRequest(requestInfo, tenantId); + Object response = new HashMap<>(); + MdmsResponse mdmsResponse = new MdmsResponse(); + try { + response = restTemplate.postForObject(uri.toString(), mdmsCriteriaReq, Map.class); + mdmsResponse = mapper.convertValue(response, MdmsResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_MDMS, e); + } + + Object result = mdmsResponse.getMdmsRes(); + if (result == null || ObjectUtils.isEmpty(result)) { + log.error(NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE + " - " + tenantId); + throw new CustomException(NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_CODE, + "no data found for the given tenantid "+tenantId + " for master name "+ServiceConstants.MDMS_MASTER_SCHEMAS); + } + return result; + } + + /** + * Constructs an MDMS request object based on the provided request information and tenant ID. + * + * @param requestInfo The request information. + * @param tenantId The ID of the tenant for which MDMS data is to be fetched. + * @return The MDMS criteria request object. + */ + public MdmsCriteriaReq getMdmsRequest(RequestInfo requestInfo, String tenantId) { + + ModuleDetail moduleDetail = getPlanModuleDetail(); + List moduleDetails = new LinkedList<>(); + moduleDetails.add(moduleDetail); + MdmsCriteria mdmsCriteria = MdmsCriteria.builder().moduleDetails(moduleDetails).tenantId(tenantId).build(); + return MdmsCriteriaReq.builder().mdmsCriteria(mdmsCriteria).requestInfo(requestInfo).build(); + } + + /** + * Retrieves the module details for the plan module. + * + * @return ModuleDetail object containing master details for the plan module. + */ + private ModuleDetail getPlanModuleDetail() { + List assumptionMasterDetails = new ArrayList<>(); + MasterDetail schemaDetails = MasterDetail.builder().name(ServiceConstants.MDMS_MASTER_SCHEMAS).build(); + assumptionMasterDetails.add(schemaDetails); + + return ModuleDetail.builder().masterDetails(assumptionMasterDetails) + .moduleName(ServiceConstants.MDMS_PLAN_MODULE_NAME).build(); + } + + /** + * Filters master data based on the provided parameters. + * + * @param masterDataJson The JSON string representing the master data. + * @param fileType The type of input file. + * @param templateIdentifier The template identifier. + * @param campaignType The campaign type. + * @return A map containing filtered properties from the master data. + * @throws JsonMappingException if there's an issue mapping JSON. + * @throws JsonProcessingException if there's an issue processing JSON. + */ + public Map filterMasterData(String masterDataJson, File.InputFileTypeEnum fileType, + String templateIdentifier, String campaignType) { + Map properties = new HashMap<>(); + Map masterData = JsonUtils.parseJson(masterDataJson, Map.class); + Map planModule = (Map) masterData.get(ServiceConstants.MDMS_PLAN_MODULE_NAME); + List> schemas = (List>) planModule + .get(ServiceConstants.MDMS_MASTER_SCHEMAS); + log.info("masterDataJson ==>" + schemas); + for (Map schema : schemas) { + String type = (String) schema.get(ServiceConstants.MDMS_SCHEMA_TYPE); + String campaign = (String) schema.get(ServiceConstants.MDMS_CAMPAIGN_TYPE); + // String fileT = InputFileTypeEnum.valueOf(type); + if (schema.get(ServiceConstants.MDMS_SCHEMA_SECTION).equals(ServiceConstants.FILE_TEMPLATE_IDENTIFIER) + && campaign.equals(campaignType) && type.equals(fileType.toString())) { + Map schemaProperties = (Map) schema.get("schema"); + properties = (Map) schemaProperties.get("Properties"); + } + } + + return properties; + } + + /** + * Parses the provided JSON string containing master data, extracts common constants, + * and returns them as a map of name-value pairs. + * + * @param masterDataJson JSON string representing master data + * @return Map containing common constants where keys are constant names and values are constant values + */ + public Map filterMasterDataForLocale(String masterDataJson) { + Map properties = new HashMap<>(); + Map masterData = JsonUtils.parseJson(masterDataJson, Map.class); + Map planModule = (Map) masterData.get(ServiceConstants.MDMS_PLAN_MODULE_NAME); + List> commonConstantsMap = (List>) planModule + .get(ServiceConstants.MDMS_MASTER_COMMON_CONSTANTS); + log.info("masterDataJson ==>" + commonConstantsMap); + for (Map commonConstantMap : commonConstantsMap) { + properties.put((String) commonConstantMap.get("name"), (String) commonConstantMap.get("value")); + + } + + return properties; + } + + /** + * Fetches MDMS (Master Data Management System) data for common constants based on the provided request info and tenant ID. + * Constructs an MDMS request, sends a POST request to the configured MDMS endpoint, and processes the response. + * + * @param requestInfo The request information containing context like user details and timestamp. + * @param tenantId The ID of the tenant for which MDMS data is requested. + * @return A filtered map of MDMS data for common constants, specific to the locale. + * @throws CustomException If no MDMS data is found for the given tenant ID. + * @throws JsonMappingException If there's an issue mapping JSON response to Java objects. + * @throws JsonProcessingException If there's an issue processing JSON during conversion. + */ + public Map fetchMdmsDataForCommonConstants(RequestInfo requestInfo, String tenantId) { + StringBuilder uri = new StringBuilder(); + uri.append(configs.getMdmsHost()).append(configs.getMdmsEndPoint()); + MdmsCriteriaReq mdmsCriteriaReq = getMdmsRequestForCommonConstants(requestInfo, tenantId); + Object response = new HashMap<>(); + MdmsResponse mdmsResponse = new MdmsResponse(); + try { + response = restTemplate.postForObject(uri.toString(), mdmsCriteriaReq, Map.class); + mdmsResponse = mapper.convertValue(response, MdmsResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_MDMS, e); + } + + Object result = mdmsResponse.getMdmsRes(); + if (result == null || ObjectUtils.isEmpty(result)) { + log.error(NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE + " - " + tenantId); + throw new CustomException(NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_CODE, + "no data found for the given tenantid "+tenantId + " for master name "+ServiceConstants.MDMS_MASTER_COMMON_CONSTANTS); + } + return filterMasterDataForLocale(result.toString()); + } + + /** + * Constructs an MDMS (Master Data Management System) request object for fetching common constants. + * + * @param requestInfo The request information containing context like user details and timestamp. + * @param tenantId The ID of the tenant for which MDMS data is requested. + * @return MdmsCriteriaReq object encapsulating the MDMS criteria for fetching common constants. + */ + public MdmsCriteriaReq getMdmsRequestForCommonConstants(RequestInfo requestInfo, String tenantId) { + + ModuleDetail moduleDetail = getPlanModulesCommonConstants(); + List moduleDetails = new LinkedList<>(); + moduleDetails.add(moduleDetail); + MdmsCriteria mdmsCriteria = MdmsCriteria.builder().moduleDetails(moduleDetails).tenantId(tenantId).build(); + return MdmsCriteriaReq.builder().mdmsCriteria(mdmsCriteria).requestInfo(requestInfo).build(); + } + + + /** + * Constructs a ModuleDetail object for fetching common constants from MDMS. + * + * @return ModuleDetail object representing the module configuration for common constants. + */ + private ModuleDetail getPlanModulesCommonConstants() { + List assumptionMasterDetails = new ArrayList<>(); + MasterDetail schemaDetails = MasterDetail.builder().name(ServiceConstants.MDMS_MASTER_COMMON_CONSTANTS).build(); + assumptionMasterDetails.add(schemaDetails); + + return ModuleDetail.builder().masterDetails(assumptionMasterDetails) + .moduleName(ServiceConstants.MDMS_PLAN_MODULE_NAME).build(); + } + +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/ParsingUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/ParsingUtil.java new file mode 100644 index 00000000000..b1902b49afb --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/ParsingUtil.java @@ -0,0 +1,249 @@ +package org.egov.processor.util; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import org.apache.commons.io.FileUtils; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.DataFormatter; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.ResourceMapping; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +public class ParsingUtil { + + private PlanConfigurationUtil planConfigurationUtil; + + private FilestoreUtil filestoreUtil; + + private CalculationUtil calculationUtil; + + public ParsingUtil(PlanConfigurationUtil planConfigurationUtil, FilestoreUtil filestoreUtil, CalculationUtil calculationUtil) { + this.planConfigurationUtil = planConfigurationUtil; + this.filestoreUtil = filestoreUtil; + this.calculationUtil = calculationUtil; + } + + public List fetchAttributeNamesFromJson(JsonNode jsonNode) + { + if(jsonNode.get("features") == null) + throw new CustomException("No Features found in geojson", " "); + List columnNames = new ArrayList<>(); + JsonNode propertiesNode = jsonNode.get("features").get(0).get("properties"); + Iterator fieldNames = propertiesNode.fieldNames(); + while (fieldNames.hasNext()) { + String columnName = fieldNames.next(); + columnNames.add(columnName); + } + return columnNames; + } + public void validateColumnNames(List columnNamesList, PlanConfiguration planConfig, String fileStoreId ) { + Set mappedFromSet = planConfig.getResourceMapping().stream() + .filter(mapping -> Objects.equals(mapping.getFilestoreId(), fileStoreId)) + .map(ResourceMapping::getMappedFrom) + .collect(Collectors.toSet()); + + for (String attributeName : mappedFromSet) { + if (attributeName.equalsIgnoreCase("the_geom")) + continue; + if (!columnNamesList.contains(attributeName)) { + log.error("Attribute mapping is invalid."); + log.info("Plan configuration doesn't contain a mapping for attribute -> " + attributeName); + throw new CustomException("Attribute mapping is invalid.", "Plan configuration doesn't contain a mapping for attribute -> " + attributeName); + } + } + + log.info("Attribute mapping is valid."); + } + + /** + * Extracts attribute names and their corresponding indices from the first row of an Excel sheet. + * + * @param sheet The Excel sheet from which to extract attribute names and indices. + * @return A sorted map containing attribute names as keys and their corresponding indices as values. + */ + public Map getAttributeNameIndexFromExcel(Sheet sheet) { + Map columnIndexMap = new HashMap<>(); + Map sortedMap = new LinkedHashMap<>(); + DataFormatter dataFormatter = new DataFormatter(); + // Assuming the first row contains column headers + Row headerRow = sheet.getRow(0); + for (int i = 0; i < headerRow.getLastCellNum(); i++) { + Cell cell = headerRow.getCell(i); + String columnHeader = dataFormatter.formatCellValue(cell); + columnIndexMap.put(columnHeader, i); + } + List> sortedColumnList = new ArrayList<>(columnIndexMap.entrySet()); + Collections.sort(sortedColumnList, (o1, o2) -> (o1.getValue()).compareTo(o2.getValue())); + for (Map.Entry entry : sortedColumnList) { + sortedMap.put(entry.getKey(), entry.getValue()); + } + return sortedMap; + } + + /** + * Converts a byte array to a File object. + * + * @param byteArray The byte array to convert. + * @param fileName The name of the file to create. + * @return The File object representing the byte array. + */ + public File convertByteArrayToFile(byte[] byteArray, String fileName) { + try { + File file = new File(fileName); + ByteArrayInputStream bis = new ByteArrayInputStream(byteArray); + FileUtils.copyInputStreamToFile(bis, file); + bis.close(); + return file; + } catch (IOException e) { + log.error("CANNOT_CONVERT_BYTE_ARRAY_TO_FILE", "Cannot convert byte array from response to File object"); + } + return null; + } + + /** + * Retrieves a file from a byte array. + * + * @param planConfig The plan configuration containing tenant and file information. + * @param fileStoreId The ID of the file store. + * @return The File object representing the byte array. + */ + public File getFileFromByteArray(PlanConfiguration planConfig, String fileStoreId) { + byte[] byteArray = filestoreUtil.getFile(planConfig.getTenantId(), fileStoreId); + return convertByteArrayToFile(byteArray, "geojson"); + } + + /** + * Converts a byte array to a String. + * + * @param planConfig The plan configuration containing tenant and file information. + * @param fileStoreId The ID of the file store. + * @return The String representation of the byte array. + */ + public String convertByteArrayToString(PlanConfiguration planConfig, String fileStoreId) { + byte[] byteArray = filestoreUtil.getFile(planConfig.getTenantId(), fileStoreId); + return new String(byteArray, StandardCharsets.UTF_8); + } + + /** + * Converts a File object containing JSON data to a String. + * + * @param geojsonFile The File object containing JSON data. + * @return The String representation of the JSON data. + */ + public String convertFileToJsonString(File geojsonFile) { + String geoJSONString = null; + try { + geoJSONString = new String(Files.readAllBytes(geojsonFile.toPath())); + } catch (IOException e) { + throw new CustomException(e.getMessage(), ""); + } + + return geoJSONString; + } + + /** + * Writes a JsonNode to a file. + * + * @param jsonNode The JsonNode to write. + * @param objectMapper The ObjectMapper used for writing the JsonNode. + * @return The File object representing the written JSON data. + */ + public File writeToFile(JsonNode jsonNode, ObjectMapper objectMapper) { + String outputFileName = "processed.geojson"; + File outputFile; + try { + String processedGeoJSON = objectMapper.writeValueAsString(jsonNode); + Object jsonObject = objectMapper.readValue(processedGeoJSON, Object.class); + outputFile = new File(outputFileName); + objectMapper.writeValue(outputFile, jsonObject); + return outputFile; + } catch (IOException e) { + throw new CustomException("NOT_ABLE_TO_WRITE_TO_FILE", "Not able to write processed geojson to file"); + } + } + + /** + * Parses a JSON string into a JsonNode. + * + * @param geoJSON The JSON string to parse. + * @param objectMapper The ObjectMapper used for parsing the JSON string. + * @return The parsed JsonNode. + */ + public JsonNode parseJson(String geoJSON, ObjectMapper objectMapper) { + try { + return objectMapper.readTree(geoJSON); + } catch (Exception e) { + log.error(e.getMessage()); + throw new CustomException("JSON_PARSE_ERROR", "Error parsing JSON: " + e.getMessage()); + } + } + + /** + * Extracts shapefiles from a zip file and returns the .shp file. + * + * @param planConfig The plan configuration containing tenant and file information. + * @param fileStoreId The ID of the file store. + * @param fileName The name of the file to extract. + * @return The extracted .shp File object. + * @throws IOException If an I/O error occurs while extracting the shapefiles. + */ + public File extractShapeFilesFromZip(PlanConfiguration planConfig, String fileStoreId, String fileName) throws IOException { + File shpFile = null; + byte[] zipFileBytes = filestoreUtil.getFile(planConfig.getTenantId(), fileStoreId); + + try (ByteArrayInputStream bais = new ByteArrayInputStream(zipFileBytes); ZipInputStream zis = new ZipInputStream(bais)) { + ZipEntry entry; + while ((entry = zis.getNextEntry()) != null) { + if (entry.getName().endsWith(".dbf")) { + String fileBaseName = entry.getName().substring(0, entry.getName().length() - 4); // Remove the .shp extension + + File tempDir = new File(System.getProperty("java.io.tmpdir") + File.separator + fileBaseName); + if (!tempDir.exists()) { + tempDir.mkdirs(); + } + + String shpFilePath = tempDir.getAbsolutePath() + File.separator + entry.getName(); + FileOutputStream fos = new FileOutputStream(shpFilePath); + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = zis.read(buffer)) != -1) { + fos.write(buffer, 0, bytesRead); + } + fos.close(); + + shpFile = new File(shpFilePath); + break; // Assuming there is only one .shp file in the zip + } + } + } + return shpFile; + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java new file mode 100644 index 00000000000..26a11dcf976 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java @@ -0,0 +1,57 @@ +package org.egov.processor.util; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import lombok.extern.slf4j.Slf4j; + +import org.egov.processor.config.Configuration; +import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationResponse; +import org.egov.processor.web.models.PlanConfigurationSearchRequest; +import org.springframework.stereotype.Component; + +import static org.egov.processor.config.ServiceConstants.ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE; + +@Component +@Slf4j +public class PlanConfigurationUtil { + + private ServiceRequestRepository serviceRequestRepository; + + private Configuration config; + + private ObjectMapper mapper; + + public PlanConfigurationUtil(ServiceRequestRepository serviceRequestRepository, Configuration config, ObjectMapper mapper) { + this.serviceRequestRepository = serviceRequestRepository; + this.config = config; + this.mapper = mapper; + } + + public List search(PlanConfigurationSearchRequest planConfigurationSearchRequest) + { + List planConfigurationList = new ArrayList<>(); + PlanConfigurationResponse planConfigurationResponse = null; + Object response = new HashMap<>(); + + StringBuilder uri = new StringBuilder(); + uri.append(config.getPlanConfigHost()).append(config.getPlanConfigEndPoint()); + + try { + response = serviceRequestRepository.fetchResult(uri, planConfigurationSearchRequest); + planConfigurationResponse = mapper.convertValue(response, PlanConfigurationResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE, e); + } + + + if(planConfigurationResponse != null) + return planConfigurationResponse.getPlanConfiguration(); + else + return planConfigurationList; + } +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanUtil.java new file mode 100644 index 00000000000..d44aaa2a59f --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanUtil.java @@ -0,0 +1,132 @@ +package org.egov.processor.util; + +import static org.egov.processor.config.ServiceConstants.ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE_FOR_LOCALITY; +import static org.egov.processor.config.ServiceConstants.PROPERTIES; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.processor.config.Configuration; +import org.egov.processor.config.ServiceConstants; +import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.processor.kafka.Producer; +import org.egov.processor.web.models.Activity; +import org.egov.processor.web.models.Plan; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.PlanConfigurationResponse; +import org.egov.processor.web.models.PlanRequest; +import org.egov.processor.web.models.Resource; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class PlanUtil { + private ServiceRequestRepository serviceRequestRepository; + + private Configuration config; + + private Producer producer; + + public PlanUtil(ServiceRequestRepository serviceRequestRepository, Configuration config, Producer producer) { + this.serviceRequestRepository = serviceRequestRepository; + this.config = config; + this.producer = producer; + } + + /** + * Creates a plan configuration request, builds a plan request from it, and pushes it to the messaging system for further processing. + * + * @param planConfigurationRequest The plan configuration request. + * @param feature The feature JSON node. + * @param resultMap The result map. + * @param mappedValues The mapped values. + */ + public void create(PlanConfigurationRequest planConfigurationRequest, JsonNode feature, + Map resultMap, Map mappedValues) { + PlanRequest planRequest = buildPlanRequest(planConfigurationRequest, feature, resultMap, mappedValues); + try { + producer.push(config.getResourceMicroplanCreateTopic(), planRequest); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE_FOR_LOCALITY + planRequest.getPlan().getLocality(), e); + } + } + + /** + * Builds a PlanRequest object using the provided plan configuration request, feature JSON node, + * result map, mapped values, and assumption value map. + * + * @param planConfigurationRequest The plan configuration request. + * @param feature The feature JSON node. + * @param resultMap The result map. + * @param mappedValues The mapped values. + * @return The constructed PlanRequest object. + */ + private PlanRequest buildPlanRequest(PlanConfigurationRequest planConfigurationRequest, JsonNode feature, + Map resultMap, Map mappedValues) { + + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + return PlanRequest.builder() + .requestInfo(planConfigurationRequest.getRequestInfo()) + .plan(Plan.builder() + .tenantId(planConfig.getTenantId()) + .executionPlanId(planConfig.getExecutionPlanId()) + .locality(getBoundaryCodeValue(ServiceConstants.BOUNDARY_CODE, + feature, mappedValues)) + .resources(resultMap.entrySet().stream().map(result -> { + Resource res = new Resource(); + res.setResourceType(result.getKey()); + res.setEstimatedNumber(result.getValue()); + return res; + }).collect(Collectors.toList())) + .activities(new ArrayList()) + .targets(new ArrayList()) + .build()) + .build(); + + } + + /** + * Retrieves the boundary code value from the feature JSON node using the mapped value for the given input. + * + * @param input The input value. + * @param feature The feature JSON node. + * @param mappedValues The mapped values. + * @return The boundary code value. + * @throws CustomException if the input value is not found in the feature JSON node. + */ + private String getBoundaryCodeValue(String input, JsonNode feature, Map mappedValues) { + if (feature.get(PROPERTIES).get(mappedValues.get(input)) != null) { + String value = String.valueOf(feature.get(PROPERTIES).get(mappedValues.get(input))); + return ((value!=null && value.length()>2)?value.substring(1, value.length()-1):value); + } + else { + throw new CustomException("INPUT_VALUE_NOT_FOUND", "Input value not found: " + input); + } + } + + /** + * Updates the plan configuration request by pushing it to the messaging system for further processing. + * + * @param planConfigurationRequest The plan configuration request to be updated. + */ + public void update(PlanConfigurationRequest planConfigurationRequest) { + + try { + producer.push(config.getResourceUpdatePlanConfigConsumerTopic(), planConfigurationRequest); + log.info("Plan Config updated because of Invalid data."); + } catch (Exception e) { + log.error(ServiceConstants.ERROR_WHILE_UPDATING_PLAN_CONFIG); + } + } +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/controllers/FileController.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/controllers/FileController.java new file mode 100644 index 00000000000..fac9d74d4d1 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/controllers/FileController.java @@ -0,0 +1,54 @@ +package org.egov.processor.web.controllers; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; +import org.egov.common.contract.request.RequestInfo; +import org.egov.processor.service.ExcelParser; +import org.egov.processor.util.ParsingUtil; +import org.egov.processor.util.PlanConfigurationUtil; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationSearchCriteria; +import org.egov.processor.web.models.PlanConfigurationSearchRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.stereotype.Controller; + + +@Controller +public class FileController { + + private ObjectMapper objectMapper; + + private ParsingUtil parsingUtil; + + private ExcelParser parser; + + private PlanConfigurationUtil planConfigurationUtil; + + @Autowired + public FileController(ObjectMapper objectMapper, ParsingUtil parsingUtil, ExcelParser parser, PlanConfigurationUtil planConfigurationUtil) { + this.objectMapper = objectMapper; + this.parsingUtil = parsingUtil; + this.parser = parser; + this.planConfigurationUtil = planConfigurationUtil; + } + + @RequestMapping(value = "/config/_test", method = RequestMethod.POST) + public ResponseEntity test() { + + PlanConfigurationSearchCriteria planConfigurationSearchCriteria = PlanConfigurationSearchCriteria.builder() + .tenantId("mz").id("b1a23c4e-a402-4047-9388-e8ae2bf7c1a3").build(); + +// id("533db2ad-cfa7-42ce-b9dc-c2877c7405ca") + PlanConfigurationSearchRequest planConfigurationSearchRequest = PlanConfigurationSearchRequest.builder().planConfigurationSearchCriteria(planConfigurationSearchCriteria).requestInfo(new RequestInfo()).build(); + List planConfigurationls = planConfigurationUtil.search(planConfigurationSearchRequest); + +// parser.parseFileData(planConfigurationls.get(0)); + return ResponseEntity.status(HttpStatus.OK).body("Okay"); + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Activity.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Activity.java new file mode 100644 index 00000000000..fa9e1193e90 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Activity.java @@ -0,0 +1,48 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * Activity + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Activity { + @JsonProperty("id") + private String id = null; + + @JsonProperty("code") + @NotNull + @Size(min = 2, max = 128) + private String code = null; + + @JsonProperty("description") + @Size(max = 2048) + private String description = null; + + @JsonProperty("plannedStartDate") + private Long plannedStartDate = null; + + @JsonProperty("plannedEndDate") + private Long plannedEndDate = null; + + @JsonProperty("dependencies") + private List dependencies = null; + + @JsonProperty("conditions") + @Valid + private List conditions = null; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Assumption.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Assumption.java new file mode 100644 index 00000000000..b8ed98d54e8 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Assumption.java @@ -0,0 +1,45 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; + +/** + * Assumption + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Assumption { + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("key") + @NotNull + @Size(min = 1, max = 256) + private String key = null; + + @JsonProperty("value") + @NotNull + @Valid + @DecimalMin(value = "0.01", inclusive = true, message = "Assumption value must be greater than 0") + @DecimalMax(value = "999.99", inclusive = true, message = "Assumption value must be less than 1000") + @Digits(integer = 3, fraction = 2, message = "Assumption value must have up to 3 digits and up to 2 decimal points") + private BigDecimal value = null; + + @JsonProperty("active") + @NotNull + private Boolean active = true; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Condition.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Condition.java new file mode 100644 index 00000000000..51d3511c068 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Condition.java @@ -0,0 +1,40 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * Condition + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Condition { + + @JsonProperty + private String id = null; + + @JsonProperty("entity") + @NotNull + @Size(min = 2, max = 64) + private String entity = null; + + @JsonProperty("entityProperty") + @NotNull + @Size(min = 2, max = 64) + private String entityProperty = null; + + @JsonProperty("expression") + @NotNull + @Size(min = 3, max = 2048) + private String expression = null; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/File.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/File.java new file mode 100644 index 00000000000..fe6b6c1abab --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/File.java @@ -0,0 +1,83 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * File + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class File { + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("filestoreId") + @NotNull + @Size(min = 1, max = 128) + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Filestore Id must contain alphanumeric characters and may include some special characters") + private String filestoreId = null; + + @JsonProperty("inputFileType") + @NotNull + private InputFileTypeEnum inputFileType = null; + + @JsonProperty("templateIdentifier") + @NotNull + @Size(min = 2, max = 128) + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Name must contain alphanumeric characters and may include some special characters") + private String templateIdentifier = null; + + @JsonProperty("active") + @NotNull + private Boolean active = true; + + /** + * The original file type of the Input + */ + public enum InputFileTypeEnum { + EXCEL("Excel"), + + SHAPEFILE("Shapefile"), + + GEOJSON("GeoJSON"); + + private String value; + + InputFileTypeEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static InputFileTypeEnum fromValue(String text) { + for (InputFileTypeEnum b : InputFileTypeEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Locale.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Locale.java new file mode 100644 index 00000000000..9de6904d989 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Locale.java @@ -0,0 +1,32 @@ +package org.egov.processor.web.models; + +import org.springframework.validation.annotation.Validated; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Represents a locale-specific message. + * This class is annotated for validation and includes Lombok annotations for generating getters, setters, constructors, and builder. + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Locale { + + // Field representing the code of the locale message + private String code; + + // Field representing the actual message in the locale + private String message; + + // Field representing the module to which the message belongs + private String module; + + // Field representing the locale identifier (e.g., "en_US") + private String locale; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/LocaleResponse.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/LocaleResponse.java new file mode 100644 index 00000000000..18a9e3f3a25 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/LocaleResponse.java @@ -0,0 +1,24 @@ +package org.egov.processor.web.models; + +import java.util.List; + +import org.springframework.validation.annotation.Validated; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Represents a response containing locale-specific messages. + * This class is annotated for validation and includes Lombok annotations for generating getters, setters, constructors, and builder. + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class LocaleResponse { + // Field representing a list of Locale messages + private List messages;; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/MetricDetail.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/MetricDetail.java new file mode 100644 index 00000000000..32a5c0b4ccc --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/MetricDetail.java @@ -0,0 +1,34 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.math.BigDecimal; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class MetricDetail { + + @JsonProperty("value") + @NotNull + private BigDecimal metricValue = null; + + @JsonProperty("comparator") + @NotNull + @Size(min = 1, max = 64) + private String metricComparator = null; + + @JsonProperty("unit") + @NotNull + @Size(min = 1, max = 128) + private String metricUnit = null; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Operation.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Operation.java new file mode 100644 index 00000000000..25b5b189fa0 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Operation.java @@ -0,0 +1,92 @@ +package org.egov.processor.web.models; + + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * Operation + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Operation { + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("input") + @NotNull + @Size(min = 1, max = 256) + private String input = null; + + @JsonProperty("operator") + @NotNull + private OperatorEnum operator = null; + + @JsonProperty("assumptionValue") + @NotNull + @Size(min = 2, max = 256) + private String assumptionValue = null; + + @JsonProperty("output") + @NotNull + @Size(min = 1, max = 64) + private String output = null; + + @JsonProperty("active") + @NotNull + private Boolean active = true; + + /** + * The operator used in the operation + */ + public enum OperatorEnum { + PLUS("+"), + + MINUS("-"), + + SLASH("/"), + + STAR("*"), + + PERCENT("%"), + + _U("**"); + + private String value; + + OperatorEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static OperatorEnum fromValue(String text) { + for (OperatorEnum b : OperatorEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Plan.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Plan.java new file mode 100644 index 00000000000..a9d4f3139b5 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Plan.java @@ -0,0 +1,63 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +/** + * Plan + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Plan { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("locality") + @Size(min = 1, max = 64) + private String locality = null; + + @JsonProperty("executionPlanId") + @Size(max = 64) + private String executionPlanId = null; + + @JsonProperty("planConfigurationId") + @Size(max = 64) + private String planConfigurationId = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("activities") + @Valid + private List activities = null; + + @JsonProperty("resources") + @Valid + private List resources = null; + + @JsonProperty("targets") + @Valid + private List targets = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfiguration.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfiguration.java new file mode 100644 index 00000000000..e02d7e49b70 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfiguration.java @@ -0,0 +1,89 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotEmpty; +import java.util.ArrayList; +import java.util.List; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import jakarta.validation.constraints.Pattern; +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * PlanConfiguration + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanConfiguration { + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("name") + @NotNull + @Size(min = 2, max = 128) + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Name must not contain only special characters") + private String name = null; + + @JsonProperty("executionPlanId") + @NotNull + @Size(min = 2, max = 64) + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Execution Plan Id must not contain only special characters") + private String executionPlanId = null; + + @JsonProperty("status") + @NotNull + private StatusEnum status = null; + + @JsonProperty("files") + @NotNull + @NotEmpty + @Valid + private List files = new ArrayList<>(); + + @JsonProperty("assumptions") + @NotNull + @NotEmpty + @Valid + private List assumptions = new ArrayList<>(); + + @JsonProperty("operations") + @NotNull + @NotEmpty + @Valid + private List operations = new ArrayList<>(); + + @JsonProperty("resourceMapping") + @NotNull + @NotEmpty + @Valid + private List resourceMapping = new ArrayList<>(); + + @JsonProperty("auditDetails") + private @Valid AuditDetails auditDetails; + + /** + * The status used in the Plan Configuration + */ + public enum StatusEnum { + DRAFT , + GENERATED, + INVALID_DATA + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationRequest.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationRequest.java new file mode 100644 index 00000000000..555db5d17e1 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationRequest.java @@ -0,0 +1,30 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * PlanConfigurationRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanConfigurationRequest { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("PlanConfiguration") + @Valid + private PlanConfiguration planConfiguration = null; + + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationResponse.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationResponse.java new file mode 100644 index 00000000000..c3892dbc869 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationResponse.java @@ -0,0 +1,40 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import java.util.ArrayList; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +/** + * PlanConfigurationResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanConfigurationResponse { + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("PlanConfiguration") + @Valid + private List planConfiguration = null; + + + public PlanConfigurationResponse addPlanConfigurationResponseItem(PlanConfiguration planConfigurationResponseItem) { + if (this.planConfiguration == null) { + this.planConfiguration = new ArrayList<>(); + } + this.planConfiguration.add(planConfigurationResponseItem); + return this; + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchCriteria.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchCriteria.java new file mode 100644 index 00000000000..b03c281067b --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchCriteria.java @@ -0,0 +1,39 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * PlanConfigurationSearchCriteria + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanConfigurationSearchCriteria { + @JsonProperty("tenantId") + @Size(min = 1, max = 100) + private String tenantId = null; + + @JsonProperty("id") + private String id = null; + + @JsonProperty("name") + private String name = null; + + @JsonProperty("executionPlanId") + private String executionPlanId = null; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchRequest.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchRequest.java new file mode 100644 index 00000000000..6b421259d15 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchRequest.java @@ -0,0 +1,30 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * PlanConfigurationSearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanConfigurationSearchRequest { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("PlanConfigurationSearchCriteria") + @Valid + private PlanConfigurationSearchCriteria planConfigurationSearchCriteria = null; + + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanRequest.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanRequest.java new file mode 100644 index 00000000000..a462e0605c0 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanRequest.java @@ -0,0 +1,30 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * PlanCreateRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanRequest { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Plan") + @Valid + private Plan plan = null; + + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Resource.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Resource.java new file mode 100644 index 00000000000..5fea454bd5d --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Resource.java @@ -0,0 +1,39 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.math.BigDecimal; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * Resource + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Resource { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("resourceType") + @NotNull + @Size(min = 2, max = 256) + private String resourceType = null; + + @JsonProperty("estimatedNumber") + @NotNull + private BigDecimal estimatedNumber = null; + + @JsonProperty("activityCode") + @Size(min = 2, max = 128) + private String activityCode = null; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/ResourceMapping.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/ResourceMapping.java new file mode 100644 index 00000000000..c53868d1033 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/ResourceMapping.java @@ -0,0 +1,47 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * ResourceMapping + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ResourceMapping { + @JsonProperty("id") + @Valid + private String id = null; + + @JsonProperty("filestoreId") + @NotNull + @Size(min = 1, max = 128) + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Filestore Id must not contain only special characters") + private String filestoreId = null; + + @JsonProperty("mappedFrom") + @NotNull + @Size(min = 2, max = 256) + private String mappedFrom = null; + + @JsonProperty("mappedTo") + @NotNull + @Size(min = 2, max = 256) + private String mappedTo = null; + + @JsonProperty("active") + @NotNull + private Boolean active = true; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Target.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Target.java new file mode 100644 index 00000000000..8d7298939f6 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Target.java @@ -0,0 +1,37 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * Target + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Target { + + @JsonProperty("id") + @Valid + private String id = null; + + @JsonProperty("metric") + private String metric = null; + + @JsonProperty("metricDetail") + @Valid + private MetricDetail metricDetail = null; + + @JsonProperty("activityCode") + @Size(min = 2, max = 128) + private String activityCode = null; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/BoundarySearchResponse.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/BoundarySearchResponse.java new file mode 100644 index 00000000000..d72d5bbc608 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/BoundarySearchResponse.java @@ -0,0 +1,45 @@ +package org.egov.processor.web.models.boundary; + +import java.util.ArrayList; +import java.util.List; + +import javax.validation.Valid; + +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * BoundarySearchResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundarySearchResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("TenantBoundary") + @Valid + private List tenantBoundary = null; + + + public BoundarySearchResponse addTenantBoundaryItem(HierarchyRelation tenantBoundaryItem) { + if (this.tenantBoundary == null) { + this.tenantBoundary = new ArrayList<>(); + } + this.tenantBoundary.add(tenantBoundaryItem); + return this; + } + +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/EnrichedBoundary.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/EnrichedBoundary.java new file mode 100644 index 00000000000..e0240d1e6d4 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/EnrichedBoundary.java @@ -0,0 +1,46 @@ +package org.egov.processor.web.models.boundary; + +import java.util.ArrayList; +import java.util.List; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * EnrichedBoundary + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class EnrichedBoundary { + + @JsonProperty("id") + private String id; + + @JsonProperty("code") + @NotNull + private String code; + + @JsonProperty("boundaryType") + private String boundaryType; + + @JsonProperty("children") + @Valid + private List children = null; + + @JsonIgnore + private String parent = null; + +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/HierarchyRelation.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/HierarchyRelation.java new file mode 100644 index 00000000000..f8de3cc5816 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/HierarchyRelation.java @@ -0,0 +1,37 @@ +package org.egov.processor.web.models.boundary; + +import java.util.List; + +import javax.validation.Valid; + +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * HierarchyRelation + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class HierarchyRelation { + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("hierarchyType") + private String hierarchyType = null; + + @JsonProperty("boundary") + @Valid + private List boundary = null; + + +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/AdditionalDetails.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/AdditionalDetails.java new file mode 100644 index 00000000000..ecaa5b6b7f1 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/AdditionalDetails.java @@ -0,0 +1,32 @@ +package org.egov.processor.web.models.campaignManager; + +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AdditionalDetails { + + @JsonProperty("key") + @Valid + private int key; + + @JsonProperty("cycleData") + @Valid + private CycleData cycleData; + + @JsonProperty("beneficiaryType") + @Valid + private String beneficiaryType; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Boundary.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Boundary.java new file mode 100644 index 00000000000..89e93500795 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Boundary.java @@ -0,0 +1,41 @@ +package org.egov.processor.web.models.campaignManager; + +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Boundary { + + @JsonProperty("code") + @NotNull + @Size(min = 1, max = 64) + private String code; + + @JsonProperty("type") + @NotNull + @Size(min = 1, max = 128) + private String type; + + @JsonProperty("isRoot") + private boolean isRoot; + + @JsonProperty("parent") + @Valid + private String parent; + + @JsonProperty("includeAllChildren") + private boolean includeAllChildren; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java new file mode 100644 index 00000000000..352b29b693b --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java @@ -0,0 +1,92 @@ +package org.egov.processor.web.models.campaignManager; + +import java.util.List; + +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Campaign { + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("id") + private String id; + + @JsonProperty("status") + @Valid + private String status; + + @JsonProperty("action") + @Size(min = 1, max = 64) + private String action; + + @JsonProperty("campaignNumber") + @Valid + private String campaignNumber; + + @JsonProperty("campaignName") + @Size(min = 2, max = 250) + private String campaignName; + + @JsonProperty("projectType") + @Size(min = 1, max = 128) + private String projectType; + + @JsonProperty("hierarchyType") + @Size(min = 1, max = 128) + private String hierarchyType; + + @JsonProperty("boundaryCode") + @Valid + private String boundaryCode; + + @JsonProperty("projectId") + @Valid + private String projectId; + + @JsonProperty("startDate") + private long startDate; + + @JsonProperty("endDate") + private long endDate; + + @JsonProperty("additionalDetails") + @Valid + private AdditionalDetails additionalDetails; + + @JsonProperty("resources") + @Valid + private List resources; + + @JsonProperty("boundaries") + @Valid + private Boundary[] boundaries = new Boundary[0]; + + @JsonProperty("deliveryRules") + @Valid + private DeliveryRule[] deliveryRules= new DeliveryRule[0]; + + @JsonProperty("auditDetails") + @Valid + private AuditDetails auditDetails; + + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignCondition.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignCondition.java new file mode 100644 index 00000000000..deec238e5c6 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignCondition.java @@ -0,0 +1,21 @@ +package org.egov.processor.web.models.campaignManager; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; + +public class CampaignCondition { + + + @JsonProperty("value") + @Valid + private Object value; // Change Object to the appropriate type + + @JsonProperty("operator") + @Valid + private Object operator; // Change Object to the appropriate type + + @JsonProperty("attribute") + @Valid + private String attribute; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignDetails.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignDetails.java new file mode 100644 index 00000000000..021c80db5a4 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignDetails.java @@ -0,0 +1,32 @@ +package org.egov.processor.web.models.campaignManager; + +import java.util.List; + +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CampaignDetails { + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("ids") + @Valid + private List ids = null; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignRequest.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignRequest.java new file mode 100644 index 00000000000..182533fbcab --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignRequest.java @@ -0,0 +1,27 @@ +package org.egov.processor.web.models.campaignManager; + +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CampaignRequest { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("CampaignDetails") + @Valid + private Campaign campaignDetails = null; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResources.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResources.java new file mode 100644 index 00000000000..b330f7bb92b --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResources.java @@ -0,0 +1,41 @@ +package org.egov.processor.web.models.campaignManager; + +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CampaignResources { + @JsonProperty("filestoreId") + @NotNull + @Size(min = 1, max = 128) + private String filestoreId = null; + + @JsonProperty("type") + @NotNull + @Size(min = 1, max = 128) + private String type = null; + + @JsonProperty("filename") + @NotNull + @Size(min = 1, max = 128) + private String filename = null; + + @JsonProperty("createResourceId") + @Valid + private String createResourceId=null; + + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResponse.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResponse.java new file mode 100644 index 00000000000..6617aeb592d --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResponse.java @@ -0,0 +1,31 @@ +package org.egov.processor.web.models.campaignManager; + +import java.util.List; + +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CampaignResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("CampaignDetails") + @Valid + private List campaign = null; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignSearchRequest.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignSearchRequest.java new file mode 100644 index 00000000000..2bfd78dab88 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignSearchRequest.java @@ -0,0 +1,28 @@ +package org.egov.processor.web.models.campaignManager; + +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CampaignSearchRequest { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("CampaignDetails") + @Valid + private CampaignDetails campaignDetails = null; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleConfigureDate.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleConfigureDate.java new file mode 100644 index 00000000000..9afd1a3c845 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleConfigureDate.java @@ -0,0 +1,29 @@ +package org.egov.processor.web.models.campaignManager; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; + +/** + * The cycle duration in days. + * This specifies the duration of the cycle for deliveries. + */ +public class CycleConfigureDate { + + /** + * The cycle duration in days. + * This specifies the duration of the cycle for deliveries. + */ + @JsonProperty("cycle") + @Valid + private int cycle; + + + /** + * The number of deliveries within the cycle. + * This indicates how many deliveries occur during each cycle period. + */ + @JsonProperty("deliveries") + @Valid + private int deliveries; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleData.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleData.java new file mode 100644 index 00000000000..ce7ae8ce080 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleData.java @@ -0,0 +1,18 @@ +package org.egov.processor.web.models.campaignManager; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; + +public class CycleData { + + @JsonProperty("cycleData") + @Valid + private List cycleData; // Change Object to the appropriate type + + @JsonProperty("cycleConfigureDate") + @Valid + private CycleConfigureDate cycleConfigureDate; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/DeliveryRule.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/DeliveryRule.java new file mode 100644 index 00000000000..44b8a3aaf0c --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/DeliveryRule.java @@ -0,0 +1,38 @@ +package org.egov.processor.web.models.campaignManager; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; + +public class DeliveryRule { + + @JsonProperty("products") + @Valid + private List products; // Change Object to the appropriate type + + @JsonProperty("conditions") + @Valid + private List conditions; + + @JsonProperty("cycleNumber") + @Valid + private int cycleNumber; + + @JsonProperty("deliveryNumber") + @Valid + private int deliveryNumber; + + @JsonProperty("deliveryRuleNumber") + @Valid + private int deliveryRuleNumber; + + @JsonProperty("endDate") + @Valid + private long endDate; + + @JsonProperty("startDate") + @Valid + private long startDate; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Product.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Product.java new file mode 100644 index 00000000000..204ab279c2a --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Product.java @@ -0,0 +1,31 @@ +package org.egov.processor.web.models.campaignManager; + +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Product { + + @JsonProperty("name") + @Valid + private String name; + + @JsonProperty("count") + @Valid + private int count; + + @JsonProperty("value") + @Valid + private String value; +} diff --git a/health-services/resource-estimation-service/src/main/resources/application.properties b/health-services/resource-estimation-service/src/main/resources/application.properties new file mode 100644 index 00000000000..7cdfe225f6d --- /dev/null +++ b/health-services/resource-estimation-service/src/main/resources/application.properties @@ -0,0 +1,83 @@ +server.contextPath=/resource-estimation-service +server.servlet.context-path=/resource-estimation-service +server.port=8083 +app.timezone=UTC + +#MANAGEMENT ENDPOINT CONFIGURATION +management.endpoints.web.base-path=/ + + +#DATABASE CONFIGURATION +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/plandb +spring.datasource.username=postgres +spring.datasource.password=postgres + +#FLYWAY CONFIGURATION +spring.flyway.url=jdbc:postgresql://localhost:5432/plandb +spring.flyway.user=postgres +spring.flyway.password=postgres +spring.flyway.table=public +spring.flyway.baseline-on-migrate=true +spring.flyway.outOfOrder=true +spring.flyway.locations=classpath:/db/migration/main +spring.flyway.enabled=false + +# KAFKA SERVER CONFIGURATIONS +kafka.config.bootstrap_server_config=localhost:9092 +spring.kafka.consumer.value-deserializer=org.egov.tracer.kafka.deserializer.HashMapDeserializer +spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer +spring.kafka.consumer.group-id=plan-service +spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer +spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer +spring.kafka.listener.missing-topics-fatal=false +spring.kafka.consumer.properties.spring.json.use.type.headers=false + +# KAFKA CONSUMER CONFIGURATIONS +kafka.consumer.config.auto_commit=true +kafka.consumer.config.auto_commit_interval=100 +kafka.consumer.config.session_timeout=15000 +kafka.consumer.config.auto_offset_reset=earliest +# KAFKA PRODUCER CONFIGURATIONS +kafka.producer.config.retries_config=0 +kafka.producer.config.batch_size_config=16384 +kafka.producer.config.linger_ms_config=1 +kafka.producer.config.buffer_memory_config=33554432 + +#mdms urls +egov.mdms.host=https://unified-dev.digit.org +egov.mdms.search.endpoint=/egov-mdms-service/v1/_search + +#plan config +egov.plan.config.host=https://unified-dev.digit.org +#egov.plan.config.host=http://localhost:8080 +egov.plan.config.endpoint=/plan-service/config/_search + +#file store +#egov.filestore.host=https://unified-dev.digit.org +egov.filestore.service.host=http://localhost:8084 + +egov.filestore.endpoint=/filestore/v1/files/id?tenantId={tenantId}&fileStoreId={fileStoreId} +egov.filestore.upload.endpoint=/filestore/v1/files + +plan.config.consumer.kafka.save.topic=plan-config-create-topic +plan.config.consumer.kafka.update.topic=plan-config-update-topic + +#Plan Create +egov.plan.create.endpoint=/plan-service/plan/_create + +#Campaign Manager +egov.project.factory.search.endpoint=/project-factory/v1/project-type/search +egov.project.factory.update.endpoint=/project-factory/v1/project-type/update +egov.project.factory.host=https://unified-dev.digit.org +#egov.project.factory.host=http://localhost:8090 +resource.microplan.create.topic=resource-microplan-create-topic +resource.update.plan.config.consumer.topic=resource-plan-config-update-topic +integrate.with.admin.console=true + +egov.boundary.service.host=https://unified-dev.digit.org +#egov.boundary.service.host=http://localhost:8091 +egov.boundary.relationship.search.endpoint=/boundary-service/boundary-relationships/_search?includeChildren=true&tenantId={tenantId}&hierarchyType={hierarchyType} + +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 diff --git a/health-services/resource-estimation-service/src/main/resources/db/Dockerfile b/health-services/resource-estimation-service/src/main/resources/db/Dockerfile new file mode 100644 index 00000000000..60fc07ce69f --- /dev/null +++ b/health-services/resource-estimation-service/src/main/resources/db/Dockerfile @@ -0,0 +1,9 @@ +FROM egovio/flyway:4.1.2 + +COPY ./migration/main /flyway/sql + +COPY migrate.sh /usr/bin/migrate.sh + +RUN chmod +x /usr/bin/migrate.sh + +CMD ["/usr/bin/migrate.sh"] \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/resources/db/migrate.sh b/health-services/resource-estimation-service/src/main/resources/db/migrate.sh new file mode 100644 index 00000000000..43960b25cdb --- /dev/null +++ b/health-services/resource-estimation-service/src/main/resources/db/migrate.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS -baselineOnMigrate=true -outOfOrder=true -ignoreMissingMigrations=true migrate \ No newline at end of file diff --git a/health-services/stock/CHANGELOG.md b/health-services/stock/CHANGELOG.md index a27826b5875..de3d5826f7a 100644 --- a/health-services/stock/CHANGELOG.md +++ b/health-services/stock/CHANGELOG.md @@ -1,5 +1,27 @@ All notable changes to this module will be documented in this file. +## 1.1.3 - 2024-05-29 +- Upgraded to Core 2.9LTS +- Upgraded to health models 1.0.20 and health common 1.0.16 +- Boundary v2 Integration +- MDMS v2 integration +- 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. + +## 1.1.1 - 2023-11-15 + - Enhanced inventory flow for last mile delivery with QR code + +## 1.1.1-beta + - Enhanced Inventory flow for last mile delivery + +## 1.1.0 + - Models library version update + ## 1.0.0 + - Base version -- Base version \ No newline at end of file diff --git a/health-services/stock/README.md b/health-services/stock/README.md index 1a507a3c922..7989b3ea73b 100644 --- a/health-services/stock/README.md +++ b/health-services/stock/README.md @@ -75,3 +75,13 @@ Stock service APIs - contains create, update, delete and search end point ## Pre commit script [commit-msg](https://gist.github.com/jayantp-egov/14f55deb344f1648503c6be7e580fa12) + +## Updates +- Stock Search + - `productVariantId`, and `waybillNumber` now accepts a list of entities instead of single entity to search stock +- Stock Reconciliation Search + - `facilityId`, and `productVariantId` now accepts a list of entities instead of single entity to search stock reconciliation +## Usage +- Start the service +- Access the API endpoints for searching `stock` and `stock reconciliation` +- Pass list parameters for the search fields mentioned in updates diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index c9502f91692..d204ba58903 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -5,16 +5,17 @@ stock jar stock - 1.0.0 + 1.1.3 - 1.8 + 17 ${java.version} ${java.version} + 1.18.22 org.springframework.boot spring-boot-starter-parent - 2.2.6.RELEASE + 3.2.2 src/main/java @@ -44,12 +45,12 @@ org.egov.common health-services-common - 1.0.8-SNAPSHOT + 1.0.18-SNAPSHOT org.egov.common health-services-models - 1.0.0-SNAPSHOT + 1.0.20-SNAPSHOT @@ -69,11 +70,17 @@ org.flywaydb flyway-core + 9.22.3 org.postgresql postgresql - 42.2.2.jre7 + 42.7.1 + + + org.egov.services + tracer + 2.9.0-SNAPSHOT org.springframework.boot @@ -90,6 +97,7 @@ org.projectlombok lombok + ${lombok.version} true @@ -97,17 +105,6 @@ com.fasterxml.jackson.datatype jackson-datatype-jsr310 - - - javax.validation - validation-api - - - org.egov.common - health-services-models - 1.0.0-SNAPSHOT - compile - diff --git a/health-services/stock/src/main/java/org/egov/stock/Constants.java b/health-services/stock/src/main/java/org/egov/stock/Constants.java index 9895af2597d..cb7589dc33f 100644 --- a/health-services/stock/src/main/java/org/egov/stock/Constants.java +++ b/health-services/stock/src/main/java/org/egov/stock/Constants.java @@ -17,12 +17,16 @@ public class Constants { public static String VALIDATION_ERROR = "VALIDATION_ERROR"; public static String GET_FACILITY_ID = "getFacilityId"; + + public static String GET_SENDER_ID = "getSenderId"; public static String GET_REFERENCE_ID = "getReferenceId"; public static String GET_TRANSACTING_PARTY_ID = "getTransactingPartyId"; public static String WAREHOUSE = "WAREHOUSE"; + + public static String STAFF = "STAFF"; public static String PROJECT = "PROJECT"; diff --git a/health-services/stock/src/main/java/org/egov/stock/config/MainConfiguration.java b/health-services/stock/src/main/java/org/egov/stock/config/MainConfiguration.java index e0d61ae0682..01fd5d00559 100644 --- a/health-services/stock/src/main/java/org/egov/stock/config/MainConfiguration.java +++ b/health-services/stock/src/main/java/org/egov/stock/config/MainConfiguration.java @@ -6,6 +6,8 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; +import com.fasterxml.jackson.databind.module.SimpleModule; +import org.egov.common.models.core.validator.CustomIntegerDeserializer; import org.egov.tracer.config.TracerConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -22,7 +24,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.util.TimeZone; @Import({TracerConfiguration.class}) @Configuration @@ -42,7 +44,12 @@ public void initialize() { @Bean public ObjectMapper objectMapper(){ - return new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).setTimeZone(TimeZone.getTimeZone(timeZone)); + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + SimpleModule module = new SimpleModule(); + module.addDeserializer(Integer.class, new CustomIntegerDeserializer()); + objectMapper.registerModule(module); + return objectMapper.setTimeZone(TimeZone.getTimeZone(timeZone)); } @Bean diff --git a/health-services/stock/src/main/java/org/egov/stock/consumer/StockConsumer.java b/health-services/stock/src/main/java/org/egov/stock/consumer/StockConsumer.java index bfa250d6097..e5b6dcf68eb 100644 --- a/health-services/stock/src/main/java/org/egov/stock/consumer/StockConsumer.java +++ b/health-services/stock/src/main/java/org/egov/stock/consumer/StockConsumer.java @@ -1,7 +1,12 @@ package org.egov.stock.consumer; +import java.util.Collections; +import java.util.List; +import java.util.Map; + import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockBulkRequest; import org.egov.stock.service.StockService; @@ -10,10 +15,6 @@ import org.springframework.messaging.handler.annotation.Header; import org.springframework.stereotype.Component; -import java.util.Collections; -import java.util.List; -import java.util.Map; - @Component @Slf4j public class StockConsumer { @@ -33,7 +34,7 @@ public List bulkCreate(Map consumerRecord, StockBulkRequest request = objectMapper.convertValue(consumerRecord, StockBulkRequest.class); return service.create(request, true); } catch (Exception exception) { - log.error("error in stock consumer bulk create", exception); + log.error("error in stock consumer bulk create: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -45,7 +46,7 @@ public List bulkUpdate(Map consumerRecord, StockBulkRequest request = objectMapper.convertValue(consumerRecord, StockBulkRequest.class); return service.update(request, true); } catch (Exception exception) { - log.error("error in stock consumer bulk update", exception); + log.error("error in stock consumer bulk update: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -57,7 +58,7 @@ public List bulkDelete(Map consumerRecord, StockBulkRequest request = objectMapper.convertValue(consumerRecord, StockBulkRequest.class); return service.delete(request, true); } catch (Exception exception) { - log.error("error in stock consumer bulk delete", exception); + log.error("error in stock consumer bulk delete: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/stock/src/main/java/org/egov/stock/consumer/StockReconciliationConsumer.java b/health-services/stock/src/main/java/org/egov/stock/consumer/StockReconciliationConsumer.java index 336197b2c15..7695c176f08 100644 --- a/health-services/stock/src/main/java/org/egov/stock/consumer/StockReconciliationConsumer.java +++ b/health-services/stock/src/main/java/org/egov/stock/consumer/StockReconciliationConsumer.java @@ -1,7 +1,12 @@ package org.egov.stock.consumer; +import java.util.Collections; +import java.util.List; +import java.util.Map; + import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.stock.StockReconciliation; import org.egov.common.models.stock.StockReconciliationBulkRequest; import org.egov.stock.service.StockReconciliationService; @@ -10,10 +15,6 @@ import org.springframework.messaging.handler.annotation.Header; import org.springframework.stereotype.Component; -import java.util.Collections; -import java.util.List; -import java.util.Map; - @Component @Slf4j public class StockReconciliationConsumer { @@ -33,7 +34,7 @@ public List bulkCreate(Map consumerRecord, StockReconciliationBulkRequest request = objectMapper.convertValue(consumerRecord, StockReconciliationBulkRequest.class); return service.create(request, true); } catch (Exception exception) { - log.error("error in stock reconciliation consumer bulk create", exception); + log.error("error in stock reconciliation consumer bulk create: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -45,7 +46,7 @@ public List bulkUpdate(Map consumerRecord, StockReconciliationBulkRequest request = objectMapper.convertValue(consumerRecord, StockReconciliationBulkRequest.class); return service.update(request, true); } catch (Exception exception) { - log.error("error in stock reconciliation consumer bulk update", exception); + log.error("error in stock reconciliation consumer bulk update: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -57,7 +58,7 @@ public List bulkDelete(Map consumerRecord, StockReconciliationBulkRequest request = objectMapper.convertValue(consumerRecord, StockReconciliationBulkRequest.class); return service.delete(request, true); } catch (Exception exception) { - log.error("error in stock reconciliation consumer bulk delete", exception); + log.error("error in stock reconciliation consumer bulk delete: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java index c8117e60ac6..813246f8a2b 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java @@ -1,16 +1,16 @@ package org.egov.stock.repository.rowmapper; +import java.sql.ResultSet; +import java.sql.SQLException; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.stock.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.stock.StockReconciliation; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import java.sql.ResultSet; -import java.sql.SQLException; - @Component public class StockReconciliationRowMapper implements RowMapper { @@ -23,6 +23,18 @@ public StockReconciliationRowMapper(ObjectMapper objectMapper) { @Override public StockReconciliation mapRow(ResultSet resultSet, int i) throws SQLException { try { + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) + .build(); return StockReconciliation.builder() .id(resultSet.getString("id")) .clientReferenceId(resultSet.getString("clientReferenceId")) @@ -39,12 +51,8 @@ public StockReconciliation mapRow(ResultSet resultSet, int i) throws SQLExceptio .isDeleted(resultSet.getBoolean("isDeleted")) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) .build(); } catch (JsonProcessingException e) { throw new SQLException(e); diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java index d443b7b4eee..e413a3052ac 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java @@ -1,18 +1,20 @@ package org.egov.stock.repository.rowmapper; +import java.sql.ResultSet; +import java.sql.SQLException; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.stock.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; +import org.egov.common.models.stock.ReferenceIdType; +import org.egov.common.models.stock.SenderReceiverType; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.TransactionReason; import org.egov.common.models.stock.TransactionType; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import java.sql.ResultSet; -import java.sql.SQLException; - @Component public class StockRowMapper implements RowMapper { @@ -21,30 +23,44 @@ public class StockRowMapper implements RowMapper { @Override public Stock mapRow(ResultSet resultSet, int i) throws SQLException { try { + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) + .build(); + Long dateOfEntry = resultSet.getLong("dateOfEntry"); + if(resultSet.wasNull()){ + dateOfEntry = null; + } return Stock.builder() .id(resultSet.getString("id")) .clientReferenceId(resultSet.getString("clientReferenceId")) .tenantId(resultSet.getString("tenantId")) - .facilityId(resultSet.getString("facilityId")) .productVariantId(resultSet.getString("productVariantId")) .quantity(resultSet.getInt("quantity")) .wayBillNumber(resultSet.getString("wayBillNumber")) .referenceId(resultSet.getString("referenceId")) - .referenceIdType(resultSet.getString("referenceIdType")) + .referenceIdType(ReferenceIdType.fromValue(resultSet.getString("referenceIdType"))) .transactionType(TransactionType.fromValue(resultSet.getString("transactionType"))) .transactionReason(TransactionReason.fromValue(resultSet.getString("transactionReason"))) - .transactingPartyId(resultSet.getString("transactingPartyId")) - .transactingPartyType(resultSet.getString("transactingPartyType")) + .senderId(resultSet.getString("senderId")) + .senderType(SenderReceiverType.fromValue(resultSet.getString("senderType"))) + .receiverId(resultSet.getString("receiverId")) + .receiverType(SenderReceiverType.fromValue(resultSet.getString("receiverType"))) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) + .dateOfEntry(dateOfEntry) .build(); } catch (JsonProcessingException e) { throw new SQLException(e); diff --git a/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java b/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java index 3a54d0ec400..2951b21e031 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java @@ -1,6 +1,13 @@ package org.egov.stock.service; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; @@ -11,13 +18,12 @@ import org.egov.common.models.project.ProjectFacilityBulkResponse; import org.egov.common.models.project.ProjectFacilitySearch; import org.egov.common.models.project.ProjectFacilitySearchRequest; +import org.egov.common.models.stock.SenderReceiverType; +import org.egov.common.models.stock.Stock; +import org.egov.common.models.stock.StockReconciliation; import org.egov.stock.config.StockConfiguration; import org.springframework.stereotype.Service; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; +import org.springframework.util.CollectionUtils; import static org.egov.common.utils.CommonUtils.getIdList; import static org.egov.common.utils.CommonUtils.getMethod; @@ -25,7 +31,6 @@ import static org.egov.common.utils.ValidatorUtils.getErrorForEntityWithNetworkError; import static org.egov.stock.Constants.GET_FACILITY_ID; import static org.egov.stock.Constants.GET_REFERENCE_ID; -import static org.egov.stock.Constants.PIPE; @Service @Slf4j @@ -40,12 +45,15 @@ public FacilityService(StockConfiguration stockConfiguration, ServiceRequestClie this.serviceRequestClient = serviceRequestClient; } - public List validateFacilityIds(List entityIds, + public List validateFacilityIds(List entityIds, List entities, String tenantId, Map> errorDetailsMap, RequestInfo requestInfo) { + if (CollectionUtils.isEmpty(entityIds)) + return Collections.emptyList(); + FacilitySearchRequest facilitySearchRequest = FacilitySearchRequest.builder() .facility(FacilitySearch.builder().id(entityIds).build()) .requestInfo(requestInfo) @@ -61,21 +69,42 @@ public List validateFacilityIds(List entityIds, FacilityBulkResponse.class); return response.getFacilities().stream().map(Facility::getId).collect(Collectors.toList()); } catch (Exception e) { - log.error("error while fetching facility list", e); - entities.forEach(b -> { + log.error("error while fetching facility list: {}", ExceptionUtils.getStackTrace(e)); + entities.forEach( stockEntity -> { Error error = getErrorForEntityWithNetworkError(); - populateErrorDetails(b, error, errorDetailsMap); + populateErrorDetails(stockEntity, error, errorDetailsMap); }); return Collections.emptyList(); } } - public List validateProjectFacilityMappings(List entities, + public Map> validateProjectFacilityMappings(List entities, String tenantId, Map> errorDetailsMap, RequestInfo requestInfo) { + + List projectIds = getIdList(entities, getMethod(GET_REFERENCE_ID, entities.get(0).getClass())); - List facilityIds = getIdList(entities, getMethod(GET_FACILITY_ID, entities.get(0).getClass())); + List facilityIds = null; + + if (entities.get(0) instanceof StockReconciliation) { + facilityIds = getIdList(entities, getMethod(GET_FACILITY_ID, entities.get(0).getClass())); + } else if (entities.get(0) instanceof Stock) { + + facilityIds = new ArrayList<>(); + for (T entity : entities) { + + Stock stock = (Stock) entity; + + if (SenderReceiverType.WAREHOUSE.equals(stock.getSenderType())) { + facilityIds.add(stock.getSenderId()); + } + if (SenderReceiverType.WAREHOUSE.equals(stock.getReceiverType())) { + facilityIds.add(stock.getReceiverId()); + } + } + } + Integer searchLimit = projectIds.size() * facilityIds.size(); ProjectFacilitySearchRequest projectFacilitySearchRequest = ProjectFacilitySearchRequest.builder() @@ -91,16 +120,18 @@ public List validateProjectFacilityMappings(List entities, + "&offset=0&tenantId=" + tenantId), projectFacilitySearchRequest, ProjectFacilityBulkResponse.class); - return response.getProjectFacilities().stream() - .map(projectFacility -> projectFacility.getFacilityId() + PIPE + projectFacility.getProjectId()) - .collect(Collectors.toList()); + + return response.getProjectFacilities().stream() + .collect(Collectors.groupingBy(projectFacility -> projectFacility.getProjectId(), + Collectors.mapping(projectFacility -> projectFacility.getFacilityId(), Collectors.toList()))); + } catch (Exception e) { - log.error("error while fetching project facility list", e); + log.error("error while fetching project facility list: {}", ExceptionUtils.getStackTrace(e)); entities.forEach(b -> { Error error = getErrorForEntityWithNetworkError(); populateErrorDetails(b, error, errorDetailsMap); }); - return Collections.emptyList(); + return Collections.emptyMap(); } } } diff --git a/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java b/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java index 718c8389a53..6c6801a5922 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java @@ -1,15 +1,24 @@ package org.egov.stock.service; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.stock.StockReconciliation; import org.egov.common.models.stock.StockReconciliationBulkRequest; import org.egov.common.models.stock.StockReconciliationRequest; +import org.egov.common.models.stock.StockReconciliationSearchRequest; import org.egov.common.validator.Validator; import org.egov.stock.config.StockReconciliationConfiguration; import org.egov.stock.repository.StockReconciliationRepository; import org.egov.stock.service.enrichment.StockReconciliationEnrichmentService; +import org.egov.stock.validator.stockreconciliation.SrExistentEntityValidator; import org.egov.stock.validator.stockreconciliation.SrFacilityIdValidator; import org.egov.stock.validator.stockreconciliation.SrIsDeletedValidator; import org.egov.stock.validator.stockreconciliation.SrNonExistentValidator; @@ -18,16 +27,9 @@ import org.egov.stock.validator.stockreconciliation.SrReferenceIdValidator; import org.egov.stock.validator.stockreconciliation.SrRowVersionValidator; import org.egov.stock.validator.stockreconciliation.SrUniqueEntityValidator; -import org.egov.stock.web.models.StockReconciliationSearchRequest; import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdMethod; import static org.egov.common.utils.CommonUtils.handleErrors; @@ -56,6 +58,7 @@ public class StockReconciliationService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(SrProductVariantIdValidator.class) + || validator.getClass().equals(SrExistentEntityValidator.class) || validator.getClass().equals(SrFacilityIdValidator.class) || validator.getClass().equals(SrReferenceIdValidator.class); @@ -97,21 +100,21 @@ public List create(StockReconciliationBulkRequest request, isBulk); Map errorDetailsMap = tuple.getY(); - List validTasks = tuple.getX(); + List validEntities = tuple.getX(); try { - if (!validTasks.isEmpty()) { - log.info("processing {} valid entities", validTasks.size()); - enrichmentService.create(validTasks, request); - stockRepository.save(validTasks, configuration.getCreateStockReconciliationTopic()); + if (!validEntities.isEmpty()) { + log.info("processing {} valid entities", validEntities.size()); + enrichmentService.create(validEntities, request); + stockRepository.save(validEntities, configuration.getCreateStockReconciliationTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); - populateErrorDetails(request, errorDetailsMap, validTasks, exception, SET_STOCK_RECONCILIATION); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_STOCK_RECONCILIATION); } handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); log.info("completed create method for stock reconciliation"); - return validTasks; + return validEntities; } public StockReconciliation update(StockReconciliationRequest request) { @@ -129,22 +132,22 @@ public List update(StockReconciliationBulkRequest request, isBulk); Map errorDetailsMap = tuple.getY(); - List validTasks = tuple.getX(); + List validEntities = tuple.getX(); try { - if (!validTasks.isEmpty()) { - log.info("processing {} valid entities", validTasks.size()); - enrichmentService.update(validTasks, request); - stockRepository.save(validTasks, configuration.getUpdateStockReconciliationTopic()); + if (!validEntities.isEmpty()) { + log.info("processing {} valid entities", validEntities.size()); + enrichmentService.update(validEntities, request); + stockRepository.save(validEntities, configuration.getUpdateStockReconciliationTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); - populateErrorDetails(request, errorDetailsMap, validTasks, exception, SET_STOCK_RECONCILIATION); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_STOCK_RECONCILIATION); } handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); log.info("completed update method for stock reconciliation"); - return validTasks; + return validEntities; } public StockReconciliation delete(StockReconciliationRequest request) { @@ -162,21 +165,21 @@ public List delete(StockReconciliationBulkRequest request, isBulk); Map errorDetailsMap = tuple.getY(); - List validTasks = tuple.getX(); + List validEntities = tuple.getX(); try { - if (!validTasks.isEmpty()) { - log.info("processing {} valid entities", validTasks.size()); - enrichmentService.delete(validTasks, request); - stockRepository.save(validTasks, configuration.getDeleteStockReconciliationTopic()); + if (!validEntities.isEmpty()) { + log.info("processing {} valid entities", validEntities.size()); + enrichmentService.delete(validEntities, request); + stockRepository.save(validEntities, configuration.getDeleteStockReconciliationTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); - populateErrorDetails(request, errorDetailsMap, validTasks, exception, SET_STOCK_RECONCILIATION); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_STOCK_RECONCILIATION); } handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); log.info("completed delete method for stock reconciliation"); - return validTasks; + return validEntities; } public List search(StockReconciliationSearchRequest request, diff --git a/health-services/stock/src/main/java/org/egov/stock/service/StockService.java b/health-services/stock/src/main/java/org/egov/stock/service/StockService.java index 8b5c232c09c..6a26da44ced 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/StockService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/StockService.java @@ -1,34 +1,36 @@ package org.egov.stock.service; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockBulkRequest; import org.egov.common.models.stock.StockRequest; +import org.egov.common.models.stock.StockSearchRequest; import org.egov.common.validator.Validator; import org.egov.stock.config.StockConfiguration; import org.egov.stock.repository.StockRepository; import org.egov.stock.service.enrichment.StockEnrichmentService; -import org.egov.stock.validator.stock.SFacilityIdValidator; +import org.egov.stock.validator.stock.SExistentEntityValidator; import org.egov.stock.validator.stock.SIsDeletedValidator; import org.egov.stock.validator.stock.SNonExistentValidator; import org.egov.stock.validator.stock.SNullIdValidator; import org.egov.stock.validator.stock.SProductVariantIdValidator; import org.egov.stock.validator.stock.SReferenceIdValidator; import org.egov.stock.validator.stock.SRowVersionValidator; -import org.egov.stock.validator.stock.STransactingPartyIdValidator; +import org.egov.stock.validator.stock.SSenderIdReceiverIdEqualsValidator; import org.egov.stock.validator.stock.SUniqueEntityValidator; -import org.egov.stock.web.models.StockSearchRequest; +import org.egov.stock.validator.stock.SStockTransferPartiesValidator; import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdMethod; import static org.egov.common.utils.CommonUtils.handleErrors; @@ -57,9 +59,10 @@ public class StockService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(SProductVariantIdValidator.class) - || validator.getClass().equals(SFacilityIdValidator.class) - || validator.getClass().equals(SReferenceIdValidator.class) - || validator.getClass().equals(STransactingPartyIdValidator.class); + || validator.getClass().equals(SExistentEntityValidator.class) + || validator.getClass().equals(SSenderIdReceiverIdEqualsValidator.class) + || validator.getClass().equals(SStockTransferPartiesValidator.class) + || validator.getClass().equals(SReferenceIdValidator.class); private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(SProductVariantIdValidator.class) @@ -68,13 +71,14 @@ public class StockService { || validator.getClass().equals(SNullIdValidator.class) || validator.getClass().equals(SRowVersionValidator.class) || validator.getClass().equals(SUniqueEntityValidator.class) - || validator.getClass().equals(SFacilityIdValidator.class) || validator.getClass().equals(SReferenceIdValidator.class) - || validator.getClass().equals(STransactingPartyIdValidator.class); + || validator.getClass().equals(SSenderIdReceiverIdEqualsValidator.class) + || validator.getClass().equals(SStockTransferPartiesValidator.class); private final Predicate> isApplicableForDelete = validator -> validator.getClass().equals(SNonExistentValidator.class) - || validator.getClass().equals(SNullIdValidator.class); + || validator.getClass().equals(SNullIdValidator.class) + || validator.getClass().equals(SRowVersionValidator.class); public StockService(StockRepository stockRepository, List> validators, StockConfiguration configuration, StockEnrichmentService enrichmentService) { this.stockRepository = stockRepository; @@ -96,21 +100,21 @@ public List create(StockBulkRequest request, boolean isBulk) { isApplicableForCreate, request, SET_STOCK, GET_STOCK, VALIDATION_ERROR, isBulk); Map errorDetailsMap = tuple.getY(); - List validTasks = tuple.getX(); + List validEntities = tuple.getX(); try { - if (!validTasks.isEmpty()) { - log.info("processing {} valid entities", validTasks.size()); - enrichmentService.create(validTasks, request); - stockRepository.save(validTasks, configuration.getCreateStockTopic()); + if (!validEntities.isEmpty()) { + log.info("processing {} valid entities", validEntities.size()); + enrichmentService.create(validEntities, request); + stockRepository.save(validEntities, configuration.getCreateStockTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); - populateErrorDetails(request, errorDetailsMap, validTasks, exception, SET_STOCK); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_STOCK); } handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); log.info("completed create method for stock"); - return validTasks; + return validEntities; } public Stock update(StockRequest request) { @@ -126,21 +130,21 @@ public List update(StockBulkRequest request, boolean isBulk) { isApplicableForUpdate, request, SET_STOCK, GET_STOCK, VALIDATION_ERROR, isBulk); Map errorDetailsMap = tuple.getY(); - List validTasks = tuple.getX(); + List validEntities = tuple.getX(); try { - if (!validTasks.isEmpty()) { - log.info("processing {} valid entities", validTasks.size()); - enrichmentService.update(validTasks, request); - stockRepository.save(validTasks, configuration.getUpdateStockTopic()); + if (!validEntities.isEmpty()) { + log.info("processing {} valid entities", validEntities.size()); + enrichmentService.update(validEntities, request); + stockRepository.save(validEntities, configuration.getUpdateStockTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); - populateErrorDetails(request, errorDetailsMap, validTasks, exception, SET_STOCK); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_STOCK); } handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); log.info("completed update method for stock"); - return validTasks; + return validEntities; } public Stock delete(StockRequest request) { @@ -156,21 +160,21 @@ public List delete(StockBulkRequest request, boolean isBulk) { isApplicableForDelete, request, SET_STOCK, GET_STOCK, VALIDATION_ERROR, isBulk); Map errorDetailsMap = tuple.getY(); - List validTasks = tuple.getX(); + List validEntities = tuple.getX(); try { - if (!validTasks.isEmpty()) { - log.info("processing {} valid entities", validTasks.size()); - enrichmentService.delete(validTasks, request); - stockRepository.save(validTasks, configuration.getDeleteStockTopic()); + if (!validEntities.isEmpty()) { + log.info("processing {} valid entities", validEntities.size()); + enrichmentService.delete(validEntities, request); + stockRepository.save(validEntities, configuration.getDeleteStockTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); - populateErrorDetails(request, errorDetailsMap, validTasks, exception, SET_STOCK); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_STOCK); } handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); log.info("completed delete method for stock"); - return validTasks; + return validEntities; } public List search(StockSearchRequest stockSearchRequest, diff --git a/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java b/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java index 92c1297cf7c..d71f92cda2d 100644 --- a/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java +++ b/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java @@ -1,17 +1,24 @@ package org.egov.stock.util; -import org.egov.common.contract.request.RequestInfo; -import org.egov.common.models.Error; -import org.egov.stock.service.FacilityService; -import org.egov.tracer.model.CustomException; -import org.springframework.util.ReflectionUtils; - import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import digit.models.coremodels.UserSearchRequest; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.ds.Tuple; +import org.egov.common.models.Error; +import org.egov.common.models.stock.SenderReceiverType; +import org.egov.common.models.stock.Stock; +import org.egov.common.models.stock.StockReconciliation; +import org.egov.common.service.UserService; +import org.egov.stock.service.FacilityService; +import org.egov.tracer.model.CustomException; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ReflectionUtils; + import static org.egov.common.utils.CommonUtils.getIdToObjMap; import static org.egov.common.utils.CommonUtils.getMethod; import static org.egov.common.utils.CommonUtils.getObjClass; @@ -19,84 +26,300 @@ import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentRelatedEntity; -import static org.egov.stock.Constants.GET_FACILITY_ID; import static org.egov.stock.Constants.GET_REQUEST_INFO; import static org.egov.stock.Constants.NO_PROJECT_FACILITY_MAPPING_EXISTS; -import static org.egov.stock.Constants.PIPE; public class ValidatorUtil { - public static Map> validateFacilityIds(R request, - Map> errorDetailsMap, - List validEntities, - String getId, - FacilityService facilityService) { - if (!validEntities.isEmpty()) { - String tenantId = getTenantId(validEntities); - Class objClass = getObjClass(validEntities); - Method idMethod = getMethod(getId, objClass); - Map eMap = getIdToObjMap(validEntities, idMethod); - RequestInfo requestInfo = (RequestInfo) ReflectionUtils.invokeMethod(getMethod(GET_REQUEST_INFO, - request.getClass()), request); - - if (!eMap.isEmpty()) { - List entityIds = new ArrayList<>(eMap.keySet()); - List existingFacilityIds = facilityService.validateFacilityIds(entityIds, - validEntities, - tenantId, errorDetailsMap, requestInfo); - List invalidEntities = validEntities.stream() - .filter(notHavingErrors()).filter(entity -> - !existingFacilityIds.contains((String) ReflectionUtils.invokeMethod(idMethod, entity))) - .collect(Collectors.toList()); - invalidEntities.forEach(entity -> { - Error error = getErrorForNonExistentRelatedEntity((String) ReflectionUtils.invokeMethod(idMethod, - entity)); - populateErrorDetails(entity, error, errorDetailsMap); - }); - } - } - - return errorDetailsMap; - } - - public static Map> validateProjectFacilityMappings(R request, - Map> errorDetailsMap, - List validEntities, - String getId, - FacilityService facilityService) { - if (!validEntities.isEmpty()) { - String tenantId = getTenantId(validEntities); - Class objClass = getObjClass(validEntities); - Method idMethod = getMethod(getId, objClass); - RequestInfo requestInfo = (RequestInfo) ReflectionUtils.invokeMethod(getMethod(GET_REQUEST_INFO, - request.getClass()), request); - - List existingProjectFacilityMappingIds = facilityService - .validateProjectFacilityMappings(validEntities, tenantId, - errorDetailsMap, requestInfo); - List invalidEntities = validEntities.stream() - .filter(notHavingErrors()).filter(entity -> - { - String comboId = (String) ReflectionUtils.invokeMethod(getMethod(GET_FACILITY_ID, objClass), - entity) - + PIPE + (String) ReflectionUtils.invokeMethod(idMethod, entity); - return !existingProjectFacilityMappingIds.contains(comboId); - }) - .collect(Collectors.toList()); - invalidEntities.forEach(entity -> { - String errorMessage = String.format("No mapping exists for project id: %s & facility id: %s", - (String) ReflectionUtils.invokeMethod(idMethod, entity), - (String) ReflectionUtils.invokeMethod(getMethod(GET_FACILITY_ID, objClass), - entity)); - Error error = Error.builder() - .errorMessage(errorMessage) - .errorCode(NO_PROJECT_FACILITY_MAPPING_EXISTS) - .type(Error.ErrorType.NON_RECOVERABLE) - .exception(new CustomException(NO_PROJECT_FACILITY_MAPPING_EXISTS, errorMessage)).build(); - populateErrorDetails(entity, error, errorDetailsMap); - }); - } - - return errorDetailsMap; - } + public static Map> validateFacilityIds(R request, Map> errorDetailsMap, + List validEntities, String getId, FacilityService facilityService) { + + if (!validEntities.isEmpty()) { + String tenantId = getTenantId(validEntities); + Class objClass = getObjClass(validEntities); + Method idMethod = getMethod(getId, objClass); + Map eMap = getIdToObjMap(validEntities, idMethod); + RequestInfo requestInfo = (RequestInfo) ReflectionUtils + .invokeMethod(getMethod(GET_REQUEST_INFO, request.getClass()), request); + + if (!eMap.isEmpty()) { + List entityIds = new ArrayList<>(eMap.keySet()); + List existingFacilityIds = facilityService.validateFacilityIds(entityIds, validEntities, + tenantId, errorDetailsMap, requestInfo); + List invalidEntities = validEntities.stream() + .filter(notHavingErrors()) + .filter(entity -> !existingFacilityIds + .contains((String) ReflectionUtils.invokeMethod(idMethod, entity))) + .collect(Collectors.toList()); + invalidEntities.forEach(entity -> { + Error error = getErrorForNonExistentRelatedEntity( + (String) ReflectionUtils.invokeMethod(idMethod, entity)); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + } + + return errorDetailsMap; + } + + /** + * Non-generic method used for validating sender/receiver (parties) against facility or staff based on the type + * + * @param requestInfo + * @param errorDetailsMap + * @param validStockEntities + * @param facilityService + * @param userService + * @return + */ + public static Map> validateStockTransferParties(RequestInfo requestInfo, + Map> errorDetailsMap, List validStockEntities, FacilityService facilityService, + UserService userService) { + + if (!validStockEntities.isEmpty()) { + + Tuple, List> tupleOfInvalidStaffIdsAndFacilityIds = validateAndEnrichInvalidPartyIds( + requestInfo, errorDetailsMap, validStockEntities, facilityService, userService); + + enrichErrorMapFromInvalidPartyIds(errorDetailsMap, validStockEntities, + tupleOfInvalidStaffIdsAndFacilityIds.getX(), tupleOfInvalidStaffIdsAndFacilityIds.getY()); + + } + return errorDetailsMap; + } + + /** + * Validates the list of party-ids (facility and staff) against the respective APIs and enriches the invalid ids list for both parties. + * + * @param requestInfo + * @param errorDetailsMap + * @param validStockEntities + * @param facilityService + * @param userService + * @return A tuple containing lists of invalid facility ids and invalid staff ids + */ + @SuppressWarnings("unchecked") + private static Tuple, List> validateAndEnrichInvalidPartyIds(RequestInfo requestInfo, + Map> errorDetailsMap, List validStockEntities, FacilityService facilityService, + UserService userService) { + + List facilityIds = new ArrayList<>(); + List staffIds = new ArrayList<>(); + + enrichFaciltyAndStaffIdsFromStock(validStockEntities, facilityIds, staffIds); + + // copy all of party identifiers into invalid list + List invalidStaffIds = new ArrayList<>(staffIds); + List invalidFacilityIds = new ArrayList<>(facilityIds); + + String tenantId = getTenantId(validStockEntities); + + // validate and remove valid identifiers from invalidStaffIds + validateAndEnrichStaffIds(requestInfo, userService, staffIds, invalidStaffIds); + + // validate and remove valid identifiers from invalidfacilityIds + List validFacilityIds = facilityService.validateFacilityIds(facilityIds, (List) validStockEntities, + tenantId, errorDetailsMap, requestInfo); + invalidFacilityIds.removeAll(validFacilityIds); + + return new Tuple<>(invalidStaffIds, invalidFacilityIds); + } + + private static void validateAndEnrichStaffIds(RequestInfo requestInfo, UserService userService, + List staffIds, List invalidStaffIds) { + if (!CollectionUtils.isEmpty(staffIds)) { + + UserSearchRequest userSearchRequest = new UserSearchRequest(); + userSearchRequest.setRequestInfo(requestInfo); + userSearchRequest.setUuid(staffIds); + List validStaffIds = userService.search(userSearchRequest).stream().map(user -> user.getUuid()) + .collect(Collectors.toList()); + invalidStaffIds.removeAll(validStaffIds); + } + } + + /** + * Private method to enrich facility id and staff id + * + * @param validStockEntities + * @param facilityIds + * @param staffIds + */ + private static void enrichFaciltyAndStaffIdsFromStock(List validStockEntities, List facilityIds, + List staffIds) { + + for (Stock stock : validStockEntities) { + + if (SenderReceiverType.WAREHOUSE.equals(stock.getSenderType()) && stock.getSenderId() != null) { + facilityIds.add(stock.getSenderId()); + } else if (SenderReceiverType.STAFF.equals(stock.getSenderType()) && stock.getSenderId() != null) { + staffIds.add(stock.getSenderId()); + } + + if (SenderReceiverType.WAREHOUSE.equals(stock.getReceiverType()) && stock.getReceiverId() != null) { + facilityIds.add(stock.getReceiverId()); + } else if (SenderReceiverType.STAFF.equals(stock.getReceiverType()) && stock.getReceiverId() != null) { + staffIds.add(stock.getReceiverId()); + } + + } + } + + /** + * + * creates the error map from the stock objects with invalid party ids + * + * @param errorDetailsMap + * @param validStockEntities + * @param invalidStaffIds + * @param invalidFacilityIds + */ + @SuppressWarnings("unchecked") + private static void enrichErrorMapFromInvalidPartyIds(Map> errorDetailsMap, + List validStockEntities, List invalidStaffIds, List invalidFacilityIds) { + + Class objClass = getObjClass(validStockEntities); + Method senderIdMethod = getMethod("getSenderId", objClass); + Method recieverIdMethod = getMethod("getReceiverId", objClass); + + for (Stock stock : validStockEntities) { + + String senderId = stock.getSenderId(); + String recieverId = stock.getReceiverId(); + + if ((SenderReceiverType.WAREHOUSE.equals(stock.getSenderType()) && invalidFacilityIds.contains(senderId)) + + || (SenderReceiverType.STAFF.equals(stock.getSenderType()) && invalidStaffIds.contains(senderId))) { + + getIdForErrorFromMethod(errorDetailsMap, (T) stock, senderIdMethod); + } + + if ((SenderReceiverType.WAREHOUSE.equals(stock.getReceiverType()) && invalidFacilityIds.contains(recieverId)) + + || (SenderReceiverType.STAFF.equals(stock.getReceiverType()) && invalidStaffIds.contains(recieverId))) { + + getIdForErrorFromMethod(errorDetailsMap, (T) stock, recieverIdMethod); + } + } + } + + /** + * method to populate error details map + * + * @param + * @param errorDetailsMap + * @param entity + * @param idMethod + */ + private static void getIdForErrorFromMethod(Map> errorDetailsMap, T entity, Method idMethod) { + + Error error = getErrorForNonExistentRelatedEntity((String) ReflectionUtils.invokeMethod(idMethod, entity)); + populateErrorDetails(entity, error, errorDetailsMap); + } + + /** + * + * @param + * @param + * @param request + * @param errorDetailsMap + * @param validEntities + * @param getReferenceId + * @param facilityService + * @return + */ + @SuppressWarnings("unchecked") + public static Map> validateProjectFacilityMappings(R request, + Map> errorDetailsMap, List validEntities, String getReferenceId, + FacilityService facilityService) { + + if (!validEntities.isEmpty()) { + + String tenantId = getTenantId(validEntities); + Class objClass = getObjClass(validEntities); + Method idMethod = getMethod(getReferenceId, objClass); + RequestInfo requestInfo = (RequestInfo) ReflectionUtils + .invokeMethod(getMethod(GET_REQUEST_INFO, request.getClass()), request); + + Map> ProjectFacilityMappingOfIds = facilityService + .validateProjectFacilityMappings((List) validEntities, tenantId, errorDetailsMap, requestInfo); + + List invalidStocks = new ArrayList<>(); + + if (validEntities.get(0) instanceof Stock) + enrichErrorForStock((List) validEntities, ProjectFacilityMappingOfIds, invalidStocks, + errorDetailsMap); + else if (validEntities.get(0) instanceof StockReconciliation) + enrichErrorForStockReconciliation((List) validEntities, + ProjectFacilityMappingOfIds, invalidStocks, errorDetailsMap); + + } + + return errorDetailsMap; + } + + @SuppressWarnings("unchecked") + private static void enrichErrorForStock(List validEntities, + Map> ProjectFacilityMappingOfIds, List invalidStocks, + Map> errorDetailsMap) { + + for (Stock stock : validEntities) { + + String senderId = stock.getSenderId(); + String receiverId = stock.getReceiverId(); + + List facilityIds = ProjectFacilityMappingOfIds.get(stock.getReferenceId()); + if (!CollectionUtils.isEmpty(facilityIds)) { + + if (SenderReceiverType.WAREHOUSE.equals(stock.getSenderType()) && !facilityIds.contains(senderId)) { + populateErrorForStock(stock, senderId, errorDetailsMap); + } + + if (SenderReceiverType.WAREHOUSE.equals(stock.getReceiverType()) && !facilityIds.contains(receiverId)) + populateErrorForStock(stock, receiverId, errorDetailsMap); + } else { + populateErrorForStock(stock, senderId + " and " + receiverId, errorDetailsMap); + } + } + } + + @SuppressWarnings("unchecked") + private static void populateErrorForStock(Stock stock, String facilityId, Map> errorDetailsMap) { + + String errorMessage = String.format("No mapping exists for project id: %s & facility id: %s", + stock.getReferenceId(), facilityId); + + Error error = Error.builder().errorMessage(errorMessage).errorCode(NO_PROJECT_FACILITY_MAPPING_EXISTS) + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException(NO_PROJECT_FACILITY_MAPPING_EXISTS, errorMessage)).build(); + populateErrorDetails((T) stock, error, errorDetailsMap); + } + + @SuppressWarnings("unchecked") + private static void enrichErrorForStockReconciliation(List validEntities, + Map> ProjectFacilityMappingOfIds, List invalidStocks, + Map> errorDetailsMap) { + + for (StockReconciliation stockReconciliation : validEntities) { + + List facilityIds = ProjectFacilityMappingOfIds.get(stockReconciliation.getReferenceId()); + if (CollectionUtils.isEmpty(facilityIds)) { + populateErrorForStockReconciliation(stockReconciliation, errorDetailsMap); + } else if (!facilityIds.contains(stockReconciliation.getFacilityId())) + populateErrorForStockReconciliation(stockReconciliation, errorDetailsMap); + } + } + + @SuppressWarnings("unchecked") + private static void populateErrorForStockReconciliation(StockReconciliation stockReconciliation, + Map> errorDetailsMap) { + + String errorMessage = String.format("No mapping exists for project id: %s & facility id: %s", + stockReconciliation.getReferenceId(), stockReconciliation.getFacilityId()); + + Error error = Error.builder().errorMessage(errorMessage).errorCode(NO_PROJECT_FACILITY_MAPPING_EXISTS) + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException(NO_PROJECT_FACILITY_MAPPING_EXISTS, errorMessage)).build(); + populateErrorDetails((T) stockReconciliation, error, errorDetailsMap); + } } diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SExistentEntityValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SExistentEntityValidator.java new file mode 100644 index 00000000000..85d5d2bf613 --- /dev/null +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SExistentEntityValidator.java @@ -0,0 +1,93 @@ +package org.egov.stock.validator.stock; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.stock.Stock; +import org.egov.common.models.stock.StockBulkRequest; +import org.egov.common.models.stock.StockSearch; +import org.egov.common.validator.Validator; +import org.egov.stock.repository.StockRepository; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of Stock entities with the given client reference IDs. + * This validator checks if the provided Stock entities already exist in the database based on their client reference IDs. + * + * @author kanishq-egov + */ +@Component +@Order(value = 1) +@Slf4j +public class SExistentEntityValidator implements Validator { + + private final StockRepository stockRepository; + + /** + * Constructor to initialize the StockRepository dependency. + * + * @param stockRepository The repository for Stock entities. + */ + public SExistentEntityValidator(StockRepository stockRepository) { + this.stockRepository = stockRepository; + } + + /** + * Validates the existence of Stock entities with the given client reference IDs. + * + * @param request The bulk request containing Stock entities. + * @return A map containing Stock entities and their associated error details. + */ + @Override + public Map> validate(StockBulkRequest request) { + // Map to hold Stock entities and their error details + Map> errorDetailsMap = new HashMap<>(); + + // Get the list of Stock entities from the request + List entities = request.getStock(); + + // Extract client reference IDs from Stock entities that do not already have errors + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) // Exclude entities with existing errors + .map(Stock::getClientReferenceId) // Map entities to their client reference IDs + .collect(Collectors.toList()); // Collect IDs into a list + + // Create a map for quick lookup of Stock entities by their client reference ID + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + + // Create a search object to query existing entities by client reference IDs + StockSearch stockSearch = StockSearch.builder() + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search + .build(); + + // Check if the list of client reference IDs is not empty + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing Stock entities with the given client reference IDs + List existingClientReferenceIds = stockRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, add an error to the map for the corresponding Stock entity + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation + Error error = getErrorForUniqueEntity(); + // Populate error details for the individual Stock entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); + }); + } + + // Return the map containing Stock entities and their associated error details + return errorDetailsMap; + } +} diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SFacilityIdValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SFacilityIdValidator.java deleted file mode 100644 index 21fa18af4a2..00000000000 --- a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SFacilityIdValidator.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.egov.stock.validator.stock; - -import lombok.extern.slf4j.Slf4j; -import org.egov.common.models.Error; -import org.egov.common.models.stock.Stock; -import org.egov.common.models.stock.StockBulkRequest; -import org.egov.common.validator.Validator; -import org.egov.stock.service.FacilityService; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.stock.Constants.GET_FACILITY_ID; -import static org.egov.stock.util.ValidatorUtil.validateFacilityIds; - -@Component -@Order(value = 7) -@Slf4j -public class SFacilityIdValidator implements Validator { - - private final FacilityService facilityService; - - public SFacilityIdValidator(FacilityService facilityService) { - this.facilityService = facilityService; - } - - @Override - public Map> validate(StockBulkRequest request) { - log.info("validating for facility id"); - Map> errorDetailsMap = new HashMap<>(); - - List validEntities = request.getStock().stream() - .filter(notHavingErrors()) - .collect(Collectors.toList()); - return validateFacilityIds(request, errorDetailsMap, validEntities, GET_FACILITY_ID, facilityService); - } -} diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SNonExistentValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SNonExistentValidator.java index 47288df7848..297613136d3 100644 --- a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SNonExistentValidator.java +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SNonExistentValidator.java @@ -1,23 +1,24 @@ package org.egov.stock.validator.stock; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockBulkRequest; +import org.egov.common.models.stock.StockSearch; import org.egov.common.validator.Validator; import org.egov.stock.repository.StockRepository; +import org.egov.tracer.model.CustomException; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdToObjMap; import static org.egov.common.utils.CommonUtils.getMethod; import static org.egov.common.utils.CommonUtils.getObjClass; @@ -46,10 +47,30 @@ public Map> validate(StockBulkRequest request) { Method idMethod = getMethod(GET_ID, objClass); Map eMap = getIdToObjMap(entities .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + // Lists to store IDs and client reference IDs + List idList = new ArrayList<>(); + List clientReferenceIdList = new ArrayList<>(); + // Extract IDs and client reference IDs from stock entities + entities.forEach(entity -> { + idList.add(entity.getId()); + clientReferenceIdList.add(entity.getClientReferenceId()); + }); if (!eMap.isEmpty()) { - List entityIds = new ArrayList<>(eMap.keySet()); - List existingEntities = stockRepository.findById(entityIds,false, - getIdFieldName(idMethod)); + StockSearch stockSearch = StockSearch.builder() + .clientReferenceId(clientReferenceIdList) + .id(idList) + .build(); + + List existingEntities; + try { + // Query the repository to find existing entities + existingEntities = stockRepository.find(stockSearch, entities.size(), 0, + entities.get(0).getTenantId(), null, false); + } catch (Exception e) { + // Handle query builder exception + log.error("Search failed for Stock with error: {}", e.getMessage(), e); + throw new CustomException("STOCK_SEARCH_FAILED", "Search Failed for Stock, " + e.getMessage()); + } List nonExistentEntities = checkNonExistentEntities(eMap, existingEntities, idMethod); nonExistentEntities.forEach(task -> { diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SReferenceIdValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SReferenceIdValidator.java index 7b791a29031..ceab1dfb887 100644 --- a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SReferenceIdValidator.java +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SReferenceIdValidator.java @@ -2,6 +2,8 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; +import org.egov.common.models.stock.ReferenceIdType; +import org.egov.common.models.stock.SenderReceiverType; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockBulkRequest; import org.egov.common.validator.Validator; @@ -37,8 +39,15 @@ public Map> validate(StockBulkRequest request) { List validEntities = request.getStock().stream() .filter(notHavingErrors()) - .filter(entity -> PROJECT.equals(entity.getReferenceIdType())) + .filter(entity -> ReferenceIdType.PROJECT.equals(entity.getReferenceIdType())) .collect(Collectors.toList()); + + long countOfWareHouseInStock = request.getStock().stream().filter(stock -> + SenderReceiverType.WAREHOUSE.equals(stock.getReceiverType()) || SenderReceiverType.WAREHOUSE.equals(stock.getSenderType()) + ).count(); + if(countOfWareHouseInStock == 0) + return errorDetailsMap; + return validateProjectFacilityMappings(request, errorDetailsMap, validEntities, GET_REFERENCE_ID, facilityService); } diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SSenderIdReceiverIdEqualsValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SSenderIdReceiverIdEqualsValidator.java new file mode 100644 index 00000000000..4285d90d26d --- /dev/null +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SSenderIdReceiverIdEqualsValidator.java @@ -0,0 +1,75 @@ +package org.egov.stock.validator.stock; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.stock.Stock; +import org.egov.common.models.stock.StockBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +/** + * Validator class to check if senderId and receiverId are equal in a list of Stock entities. + */ +@Component +@Order(value = 6) +@Slf4j +public class SSenderIdReceiverIdEqualsValidator implements Validator { + + /** + * Validates the list of Stock entities to ensure that senderId and receiverId are not equal. + * + * @param stockBulkRequest The bulk request containing a list of Stock entities. + * @return A map containing Stock entities with corresponding error details for entities with equal senderId and receiverId. + */ + @Override + public Map> validate(StockBulkRequest stockBulkRequest) { + Map> errorDetailsMap = new HashMap<>(); + List entities = stockBulkRequest.getStock(); + List invalidEntities = new ArrayList<>(); + log.info("validating whether sender id and receiver id are same"); + + // Iterate through each Stock entity in the list + entities.forEach(stock -> { + // Check if senderId and receiverId are equal using helper method + if (areSenderAndReceiverEqual(stock)) { + // If equal, add the entity to the list of invalid entities + invalidEntities.add(stock); + + // Create an error object for the entity + Error error = Error.builder() + .errorMessage("Sender Id and Receiver Id cannot be the same") + .errorCode("SENDER_RECEIVER_CANNOT_BE_EQUAL") + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException("SENDER_RECEIVER_CANNOT_BE_EQUAL", "Sender Id and Receiver Id cannot be the same")) + .build(); + + // Populate error details for the entity + populateErrorDetails(stock, error, errorDetailsMap); + } + }); + + return errorDetailsMap; + } + + /** + * Helper method to check if senderId and receiverId are equal. + * + * @param stock The Stock entity to check. + * @return True if senderId and receiverId are equal, false otherwise. + */ + private boolean areSenderAndReceiverEqual(Stock stock) { + return stock.getSenderType() == stock.getReceiverType() + && stock.getReceiverId() != null + && stock.getSenderId() != null + && stock.getReceiverId().equals(stock.getSenderId()); + } +} diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SStockTransferPartiesValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SStockTransferPartiesValidator.java new file mode 100644 index 00000000000..7be98ea1199 --- /dev/null +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SStockTransferPartiesValidator.java @@ -0,0 +1,48 @@ +package org.egov.stock.validator.stock; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.stock.util.ValidatorUtil.validateStockTransferParties; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.common.models.Error; +import org.egov.common.models.stock.Stock; +import org.egov.common.models.stock.StockBulkRequest; +import org.egov.common.service.UserService; +import org.egov.common.validator.Validator; +import org.egov.stock.service.FacilityService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Order(value = 7) +@Slf4j +public class SStockTransferPartiesValidator implements Validator { + + private final FacilityService facilityService; + + private UserService userService; + + @Autowired + public SStockTransferPartiesValidator(FacilityService facilityService, UserService userService) { + this.facilityService = facilityService; + this.userService = userService; + } + + @Override + public Map> validate(StockBulkRequest request) { + log.info("validating for facility id"); + Map> errorDetailsMap = new HashMap<>(); + + List validEntities = request.getStock().stream().filter(notHavingErrors()).collect(Collectors.toList()); + + return validateStockTransferParties(request.getRequestInfo(), errorDetailsMap, validEntities, facilityService, + userService); + } +} diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/STransactingPartyIdValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/STransactingPartyIdValidator.java deleted file mode 100644 index 5e7604e635f..00000000000 --- a/health-services/stock/src/main/java/org/egov/stock/validator/stock/STransactingPartyIdValidator.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.egov.stock.validator.stock; - -import lombok.extern.slf4j.Slf4j; -import org.egov.common.models.Error; -import org.egov.common.models.stock.Stock; -import org.egov.common.models.stock.StockBulkRequest; -import org.egov.common.validator.Validator; -import org.egov.stock.service.FacilityService; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.stock.Constants.GET_TRANSACTING_PARTY_ID; -import static org.egov.stock.Constants.WAREHOUSE; -import static org.egov.stock.util.ValidatorUtil.validateFacilityIds; - -@Component -@Order(value = 9) -@Slf4j -public class STransactingPartyIdValidator implements Validator { - - private final FacilityService facilityService; - - public STransactingPartyIdValidator(FacilityService facilityService) { - this.facilityService = facilityService; - } - - @Override - public Map> validate(StockBulkRequest request) { - log.info("validating for reference id"); - Map> errorDetailsMap = new HashMap<>(); - - List validFacilityTransactingPartyIdEntities = request.getStock().stream() - .filter(notHavingErrors()) - .filter(entity -> WAREHOUSE.equals(entity.getTransactingPartyType())) - .collect(Collectors.toList()); - return validateFacilityIds(request, errorDetailsMap, validFacilityTransactingPartyIdEntities, - GET_TRANSACTING_PARTY_ID, facilityService); - } -} diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrExistentEntityValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrExistentEntityValidator.java new file mode 100644 index 00000000000..6917135941a --- /dev/null +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrExistentEntityValidator.java @@ -0,0 +1,94 @@ +package org.egov.stock.validator.stockreconciliation; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.stock.StockReconciliation; +import org.egov.common.models.stock.StockReconciliationBulkRequest; +import org.egov.common.models.stock.StockReconciliationSearch; +import org.egov.common.validator.Validator; +import org.egov.stock.repository.StockReconciliationRepository; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of StockReconciliation entities with the given client reference IDs. + * This validator checks if the provided StockReconciliation entities already exist in the database based on their client reference IDs. + * + * @author kanishq-egov + */ +@Component +@Order(value = 1) +@Slf4j +public class SrExistentEntityValidator implements Validator { + + private final StockReconciliationRepository stockReconciliationRepository; + + /** + * Constructor to initialize the StockReconciliationRepository dependency. + * + * @param stockReconciliationRepository The repository for StockReconciliation entities. + */ + public SrExistentEntityValidator(StockReconciliationRepository stockReconciliationRepository) { + this.stockReconciliationRepository = stockReconciliationRepository; + } + + /** + * Validates the existence of StockReconciliation entities with the given client reference IDs. + * + * @param request The bulk request containing StockReconciliation entities. + * @return A map containing StockReconciliation entities and their associated error details. + */ + @Override + public Map> validate(StockReconciliationBulkRequest request) { + // Map to hold StockReconciliation entities and their error details + Map> errorDetailsMap = new HashMap<>(); + + // Get the list of StockReconciliation entities from the request + List entities = request.getStockReconciliation(); + + // Extract client reference IDs from StockReconciliation entities that do not already have errors + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) // Filter out entities with existing errors + .map(StockReconciliation::getClientReferenceId) // Map entities to their client reference IDs + .collect(Collectors.toList()); // Collect IDs into a list + + // Create a map for quick lookup of StockReconciliation entities by their client reference ID + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + + // Create a search object to query existing entities by client reference IDs + StockReconciliationSearch stockReconciliationSearch = StockReconciliationSearch.builder() + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search + .build(); + + // Check if the list of client reference IDs is not empty + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing StockReconciliation entities with the given client reference IDs + List existingClientReferenceIds = + stockReconciliationRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, add an error to the map for the corresponding StockReconciliation entity + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation + Error error = getErrorForUniqueEntity(); + // Populate error details for the individual StockReconciliation entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); + }); + } + + // Return the map containing StockReconciliation entities and their associated error details + return errorDetailsMap; + } +} diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrNonExistentValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrNonExistentValidator.java index d1975a10872..389cc2a2460 100644 --- a/health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrNonExistentValidator.java +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrNonExistentValidator.java @@ -1,23 +1,24 @@ package org.egov.stock.validator.stockreconciliation; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; import org.egov.common.models.stock.StockReconciliation; import org.egov.common.models.stock.StockReconciliationBulkRequest; +import org.egov.common.models.stock.StockReconciliationSearch; import org.egov.common.validator.Validator; import org.egov.stock.repository.StockReconciliationRepository; +import org.egov.tracer.model.CustomException; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdToObjMap; import static org.egov.common.utils.CommonUtils.getMethod; import static org.egov.common.utils.CommonUtils.getObjClass; @@ -46,10 +47,30 @@ public Map> validate(StockReconciliationBulkReq Method idMethod = getMethod(GET_ID, objClass); Map eMap = getIdToObjMap(entities .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + // Lists to store IDs and client reference IDs + List idList = new ArrayList<>(); + List clientReferenceIdList = new ArrayList<>(); + // Extract IDs and client reference IDs from StockReconciliation entities + entities.forEach(entity -> { + idList.add(entity.getId()); + clientReferenceIdList.add(entity.getClientReferenceId()); + }); if (!eMap.isEmpty()) { - List entityIds = new ArrayList<>(eMap.keySet()); - List existingEntities = stockReconciliationRepository.findById(entityIds,false, - getIdFieldName(idMethod)); + StockReconciliationSearch stockReconciliationSearch = StockReconciliationSearch.builder() + .clientReferenceId(clientReferenceIdList) + .id(idList) + .build(); + + List existingEntities; + try { + // Query the repository to find existing entities + existingEntities = stockReconciliationRepository.find(stockReconciliationSearch, entities.size(), 0, + entities.get(0).getTenantId(), null, false); + } catch (Exception e) { + // Handle query builder exception + log.error("Search failed for StockReconciliation with error: {}", e.getMessage(), e); + throw new CustomException("STOCK_RECONCILIANTION_SEARCH_FAILED", "Search Failed for StockReconciliation, " + e.getMessage()); + } List nonExistentEntities = checkNonExistentEntities(eMap, existingEntities, idMethod); nonExistentEntities.forEach(task -> { diff --git a/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockApiController.java b/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockApiController.java index 5fb0aef98b4..913213dd191 100644 --- a/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockApiController.java +++ b/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockApiController.java @@ -1,36 +1,34 @@ package org.egov.stock.web.controllers; +import java.util.List; + import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.URLParams; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockBulkRequest; import org.egov.common.models.stock.StockBulkResponse; import org.egov.common.models.stock.StockRequest; import org.egov.common.models.stock.StockResponse; +import org.egov.common.models.stock.StockSearchRequest; import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; import org.egov.stock.config.StockConfiguration; import org.egov.stock.service.StockService; -import org.egov.stock.web.models.StockSearchRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.util.List; -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") @Controller @RequestMapping("") @@ -77,13 +75,21 @@ public ResponseEntity stockV1CreatePost(@ApiParam(value = "Capture } @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) - public ResponseEntity stockV1SearchPost(@ApiParam(value = "Capture details of Stock Transfer.", required = true) @Valid @RequestBody StockSearchRequest request, @NotNull - @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull - @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { - - List stock = stockService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); + public ResponseEntity stockV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Capture details of Stock Transfer.", required = true) @Valid @RequestBody StockSearchRequest stockSearchRequest + ) throws Exception { + + List stock = stockService.search( + stockSearchRequest, + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() + ); StockBulkResponse response = StockBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).stock(stock).build(); + .createResponseInfo(stockSearchRequest.getRequestInfo(), true)).stock(stock).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockReconciliationApiController.java b/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockReconciliationApiController.java index 96633e81891..e612c3b692f 100644 --- a/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockReconciliationApiController.java +++ b/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockReconciliationApiController.java @@ -1,32 +1,30 @@ package org.egov.stock.web.controllers; +import java.util.List; + import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.URLParams; import org.egov.common.models.stock.StockReconciliation; import org.egov.common.models.stock.StockReconciliationBulkRequest; import org.egov.common.models.stock.StockReconciliationBulkResponse; import org.egov.common.models.stock.StockReconciliationRequest; import org.egov.common.models.stock.StockReconciliationResponse; +import org.egov.common.models.stock.StockReconciliationSearchRequest; import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; import org.egov.stock.config.StockReconciliationConfiguration; import org.egov.stock.service.StockReconciliationService; -import org.egov.stock.web.models.StockReconciliationSearchRequest; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; - -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.util.List; @Controller @RequestMapping("") @@ -74,14 +72,21 @@ public ResponseEntity stockReconciliationV1CreatePost(@ApiParam(va } @RequestMapping(value = "/reconciliation/v1/_search", method = RequestMethod.POST) - public ResponseEntity stockReconciliationV1SearchPost(@ApiParam(value = "Capture details of Stock Reconciliation.", required = true) @Valid @RequestBody StockReconciliationSearchRequest request, @NotNull - @Min(0) - @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull - @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { - - List stock = stockReconciliationService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); + public ResponseEntity stockReconciliationV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Capture details of Stock Reconciliation.", required = true) @Valid @RequestBody StockReconciliationSearchRequest stockReconciliationSearchRequest + ) throws Exception { + + List stock = stockReconciliationService.search( + stockReconciliationSearchRequest, + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() + ); StockReconciliationBulkResponse response = StockReconciliationBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).stockReconciliation(stock).build(); + .createResponseInfo(stockReconciliationSearchRequest.getRequestInfo(), true)).stockReconciliation(stock).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/stock/src/main/java/org/egov/stock/web/models/StockReconciliationSearch.java b/health-services/stock/src/main/java/org/egov/stock/web/models/StockReconciliationSearch.java deleted file mode 100644 index 47aa3ea28d1..00000000000 --- a/health-services/stock/src/main/java/org/egov/stock/web/models/StockReconciliationSearch.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.egov.stock.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Table; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.Size; -import java.util.List; - -/** - * StockReconciliationSearch - */ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -@Table(name = "stock_reconciliation_log") -public class StockReconciliationSearch { - @JsonProperty("id") - @Valid - private List id = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; - - @JsonProperty("facilityId") - @Size(min=2, max=64) - private String facilityId = null; - - @JsonProperty("productVariantId") - @Size(min=2, max=64) - private String productVariantId = null; -} - diff --git a/health-services/stock/src/main/java/org/egov/stock/web/models/StockReconciliationSearchRequest.java b/health-services/stock/src/main/java/org/egov/stock/web/models/StockReconciliationSearchRequest.java deleted file mode 100644 index e09efe6db86..00000000000 --- a/health-services/stock/src/main/java/org/egov/stock/web/models/StockReconciliationSearchRequest.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.egov.stock.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -/** - * StockReconciliationSearchRequest - */ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class StockReconciliationSearchRequest { - @JsonProperty("RequestInfo") - @NotNull - @Valid - private org.egov.common.contract.request.RequestInfo requestInfo = null; - - @JsonProperty("StockReconciliation") - @NotNull - @Valid - private StockReconciliationSearch stockReconciliation = null; - - -} - diff --git a/health-services/stock/src/main/java/org/egov/stock/web/models/StockSearch.java b/health-services/stock/src/main/java/org/egov/stock/web/models/StockSearch.java deleted file mode 100644 index 2c5e574878c..00000000000 --- a/health-services/stock/src/main/java/org/egov/stock/web/models/StockSearch.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.egov.stock.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Table; -import org.egov.common.models.stock.TransactionReason; -import org.egov.common.models.stock.TransactionType; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.Size; -import java.util.List; - -/** - * StockSearch - */ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -@Table(name="stock") -public class StockSearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; - - @JsonProperty("facilityId") - @Size(min=2, max=64) - private String facilityId = null; - - @JsonProperty("productVariantId") - @Size(min=2, max=64) - private String productVariantId = null; - - @JsonProperty("referenceId") - private String referenceId = null; - - @JsonProperty("wayBillNumber") - private String wayBillNumber = null; - - @JsonProperty("referenceIdType") - @Size(min=2, max=64) - private String referenceIdType = null; - - @JsonProperty("transactionType") - @Valid - private TransactionType transactionType = null; - - @JsonProperty("transactionReason") - @Valid - private TransactionReason transactionReason = null; - - @JsonProperty("transactingPartyId") - @Size(min=2, max=64) - private String transactingPartyId = null; - - @JsonProperty("transactingPartyType") - private String transactingPartyType = null; -} - diff --git a/health-services/stock/src/main/resources/application.properties b/health-services/stock/src/main/resources/application.properties index 007aa1f216a..47372ce87b1 100644 --- a/health-services/stock/src/main/resources/application.properties +++ b/health-services/stock/src/main/resources/application.properties @@ -59,12 +59,15 @@ stock.reconciliation.idgen.id.format=stock.reconciliation.id # The value of the following field should be changed to service specific name kafka.topics.consumer=stock-consumer-topic + # USER CONFIG +egov.user.integration.enabled=true egov.user.host=https://dev.digit.org egov.user.context.path=/user/users -egov.user.create.path=/_createnovalidate -egov.user.search.path=/user/_search -egov.user.update.path=/_updatenovalidate +egov.create.user.path=/_createnovalidate +egov.create.user.url=/_createnovalidate +egov.search.user.url=/user/_search +egov.update.user.url=/_updatenovalidate # MDMS CONFIG egov.mdms.host=https://dev.digit.org diff --git a/health-services/stock/src/main/resources/db/Dockerfile b/health-services/stock/src/main/resources/db/Dockerfile index 60fc07ce69f..e7da01d7f0b 100644 --- a/health-services/stock/src/main/resources/db/Dockerfile +++ b/health-services/stock/src/main/resources/db/Dockerfile @@ -1,4 +1,4 @@ -FROM egovio/flyway:4.1.2 +FROM egovio/flyway:10.7.1 COPY ./migration/main /flyway/sql @@ -6,4 +6,4 @@ COPY migrate.sh /usr/bin/migrate.sh RUN chmod +x /usr/bin/migrate.sh -CMD ["/usr/bin/migrate.sh"] \ No newline at end of file +ENTRYPOINT ["/usr/bin/migrate.sh"] \ No newline at end of file diff --git a/health-services/stock/src/main/resources/db/migrate.sh b/health-services/stock/src/main/resources/db/migrate.sh index 43960b25cdb..f9d6617822c 100644 --- a/health-services/stock/src/main/resources/db/migrate.sh +++ b/health-services/stock/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/stock/src/main/resources/db/migration/main/V20230612103737__stock_dateOfEntry_column_ddl.sql b/health-services/stock/src/main/resources/db/migration/main/V20230612103737__stock_dateOfEntry_column_ddl.sql new file mode 100644 index 00000000000..af90c0d36ef --- /dev/null +++ b/health-services/stock/src/main/resources/db/migration/main/V20230612103737__stock_dateOfEntry_column_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE STOCK ADD COLUMN dateOfEntry bigint; diff --git a/health-services/stock/src/main/resources/db/migration/main/V20230628181500__add_client_audit_details_in_stock_ddl.sql b/health-services/stock/src/main/resources/db/migration/main/V20230628181500__add_client_audit_details_in_stock_ddl.sql new file mode 100644 index 00000000000..94c9be7e697 --- /dev/null +++ b/health-services/stock/src/main/resources/db/migration/main/V20230628181500__add_client_audit_details_in_stock_ddl.sql @@ -0,0 +1,5 @@ +ALTER TABLE STOCK ADD COLUMN clientCreatedTime bigint; +ALTER TABLE STOCK ADD COLUMN clientLastModifiedTime bigint; + +ALTER TABLE STOCK_RECONCILIATION_LOG ADD COLUMN clientCreatedTime bigint; +ALTER TABLE STOCK_RECONCILIATION_LOG ADD COLUMN clientLastModifiedTime bigint; \ No newline at end of file diff --git a/health-services/stock/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_stock_ddl.sql b/health-services/stock/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_stock_ddl.sql new file mode 100644 index 00000000000..97b8cdd0688 --- /dev/null +++ b/health-services/stock/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_stock_ddl.sql @@ -0,0 +1,5 @@ +ALTER TABLE STOCK ADD COLUMN IF NOT EXISTS clientCreatedBy character varying(64); +ALTER TABLE STOCK ADD COLUMN IF NOT EXISTS clientLastModifiedBy character varying(64); + +ALTER TABLE STOCK_RECONCILIATION_LOG ADD COLUMN IF NOT EXISTS clientCreatedBy character varying(64); +ALTER TABLE STOCK_RECONCILIATION_LOG ADD COLUMN IF NOT EXISTS clientLastModifiedBy character varying(64); diff --git a/health-services/stock/src/main/resources/db/migration/main/V20231005182626__alter_stock_add_transaction_parties.sql b/health-services/stock/src/main/resources/db/migration/main/V20231005182626__alter_stock_add_transaction_parties.sql new file mode 100644 index 00000000000..e8794b86346 --- /dev/null +++ b/health-services/stock/src/main/resources/db/migration/main/V20231005182626__alter_stock_add_transaction_parties.sql @@ -0,0 +1,4 @@ +ALTER TABLE STOCK ADD COLUMN IF NOT EXISTS senderType character varying(128); +ALTER TABLE STOCK ADD COLUMN IF NOT EXISTS receiverType character varying(128); +ALTER TABLE STOCK ADD COLUMN IF NOT EXISTS senderid character varying(128); +ALTER TABLE STOCK ADD COLUMN IF NOT EXISTS receiverid character varying(128); diff --git a/health-services/stock/src/test/java/org/egov/stock/TestConfiguration.java b/health-services/stock/src/test/java/org/egov/stock/TestConfiguration.java index 0d8d9758688..d507efd67c1 100644 --- a/health-services/stock/src/test/java/org/egov/stock/TestConfiguration.java +++ b/health-services/stock/src/test/java/org/egov/stock/TestConfiguration.java @@ -1,5 +1,11 @@ package org.egov.stock; +import java.util.TimeZone; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import org.egov.common.models.core.validator.CustomIntegerDeserializer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.kafka.core.KafkaTemplate; @@ -13,4 +19,14 @@ public class TestConfiguration { public KafkaTemplate kafkaTemplate() { return mock(KafkaTemplate.class); } + + @Bean + public ObjectMapper objectMapper(){ + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + SimpleModule module = new SimpleModule(); + module.addDeserializer(Integer.class, new CustomIntegerDeserializer()); + objectMapper.registerModule(module); + return objectMapper.setTimeZone(TimeZone.getTimeZone("UTC")); + } } \ No newline at end of file diff --git a/health-services/stock/src/test/java/org/egov/stock/helper/StockReconciliationTestBuilder.java b/health-services/stock/src/test/java/org/egov/stock/helper/StockReconciliationTestBuilder.java index 616b726e29a..e841f6af674 100644 --- a/health-services/stock/src/test/java/org/egov/stock/helper/StockReconciliationTestBuilder.java +++ b/health-services/stock/src/test/java/org/egov/stock/helper/StockReconciliationTestBuilder.java @@ -1,15 +1,16 @@ package org.egov.stock.helper; import org.egov.common.helper.AuditDetailsTestBuilder; +import org.egov.common.models.household.Household; import org.egov.common.models.stock.StockReconciliation; public class StockReconciliationTestBuilder { - private final StockReconciliation.StockReconciliationBuilder builder; + private final StockReconciliation.StockReconciliationBuilder builder; public StockReconciliationTestBuilder() { - this.builder = StockReconciliation.builder(); + this.builder = (StockReconciliation.StockReconciliationBuilder) StockReconciliation.builder(); } public static StockReconciliationTestBuilder builder() { @@ -21,7 +22,7 @@ public StockReconciliation build() { } public StockReconciliationTestBuilder withStock() { - this.builder.facilityId("facility-id").productVariantId("pv-id").physicalCount(10) + this.builder.facilityId("sender-id").productVariantId("pv-id").physicalCount(10) .calculatedCount(100).referenceId("reference-id") .referenceIdType("PROJECT").rowVersion(1).tenantId("default").hasErrors(false).isDeleted(Boolean.FALSE) .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); diff --git a/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java b/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java index d755e8fd06d..7499c8e92f4 100644 --- a/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java +++ b/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java @@ -1,6 +1,8 @@ package org.egov.stock.helper; import org.egov.common.helper.AuditDetailsTestBuilder; +import org.egov.common.models.stock.ReferenceIdType; +import org.egov.common.models.stock.SenderReceiverType; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.TransactionReason; import org.egov.common.models.stock.TransactionType; @@ -8,10 +10,10 @@ public class StockTestBuilder { - private final Stock.StockBuilder builder; + private final Stock.StockBuilder builder; public StockTestBuilder() { - this.builder = Stock.builder(); + this.builder = (Stock.StockBuilder) Stock.builder(); } public static StockTestBuilder builder() { @@ -23,11 +25,22 @@ public Stock build() { } public StockTestBuilder withStock() { - this.builder.facilityId("facility-id").productVariantId("pv-id").quantity(0).referenceId("reference-id") - .referenceIdType("PROJECT").rowVersion(1).tenantId("default").transactingPartyId("transaction-party-id") - .transactionType(TransactionType.DISPATCHED).transactionReason(TransactionReason.RECEIVED) - .transactingPartyType("WAREHOUSE").hasErrors(false).isDeleted(Boolean.FALSE) - .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); + this.builder + .senderId("sender-id") + .receiverId("receiver-id") + .productVariantId("pv-id") + .quantity(1) + .referenceId("reference-id") + .referenceIdType(ReferenceIdType.PROJECT) + .rowVersion(1) + .tenantId("default") + .transactionType(TransactionType.DISPATCHED) + .transactionReason(TransactionReason.RECEIVED) + .senderType(SenderReceiverType.WAREHOUSE) + .receiverType(SenderReceiverType.STAFF) + .hasErrors(false) + .isDeleted(Boolean.FALSE) + .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); return this; } diff --git a/health-services/stock/src/test/java/org/egov/stock/validator/FacilityIdValidatorTest.java b/health-services/stock/src/test/java/org/egov/stock/validator/FacilityIdValidatorTest.java deleted file mode 100644 index ad7e257a488..00000000000 --- a/health-services/stock/src/test/java/org/egov/stock/validator/FacilityIdValidatorTest.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.egov.stock.validator; - - -import org.egov.common.contract.request.RequestInfo; -import org.egov.common.models.Error; -import org.egov.common.models.stock.Stock; -import org.egov.common.models.stock.StockBulkRequest; -import org.egov.common.models.stock.StockReconciliation; -import org.egov.common.models.stock.StockReconciliationBulkRequest; -import org.egov.stock.helper.StockBulkRequestTestBuilder; -import org.egov.stock.helper.StockReconciliationBulkRequestTestBuilder; -import org.egov.stock.service.FacilityService; -import org.egov.stock.validator.stock.SFacilityIdValidator; -import org.egov.stock.validator.stockreconciliation.SrFacilityIdValidator; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -class FacilityIdValidatorTest { - - @InjectMocks - private SFacilityIdValidator sFacilityIdValidator; - - @InjectMocks - private SrFacilityIdValidator srFacilityIdValidator; - - @Mock - private FacilityService facilityService; - - private void mockEmptyResponse() { - when(facilityService.validateFacilityIds(any(List.class), - any(List.class), - any(String.class), - any(Map.class), - any(RequestInfo.class))).thenReturn(Collections.emptyList()); - } - - private void mockSomeResponse() { - when(facilityService.validateFacilityIds(any(List.class), - any(List.class), - any(String.class), - any(Map.class), - any(RequestInfo.class))).thenReturn(Collections.singletonList("facility-id")); - } - - @Test - @DisplayName("should add stock to error details if facility id not found") - void shouldAddStockToErrorDetailsIfFacilityIdNotFound() { - StockBulkRequest request = StockBulkRequestTestBuilder.builder().withStock().withRequestInfo().build(); - - mockEmptyResponse(); - - Map> errorDetailsMap = sFacilityIdValidator.validate(request); - assertEquals(errorDetailsMap.size(), 1); - } - - @Test - @DisplayName("should not add stock to error details if facility id found") - void shouldAddStockToErrorDetailsIfFacilityIdFound() { - StockBulkRequest request = StockBulkRequestTestBuilder.builder().withStock().withRequestInfo().build(); - - mockSomeResponse(); - - Map> errorDetailsMap = sFacilityIdValidator.validate(request); - assertEquals(errorDetailsMap.size(), 0); - } - - @Test - @DisplayName("should add stock reconciliation to error details if facility id not found") - void shouldAddStockReconciliationToErrorDetailsFacilityIdNotFound() { - StockReconciliationBulkRequest request = StockReconciliationBulkRequestTestBuilder.builder() - .withStock().withRequestInfo().build(); - - mockEmptyResponse(); - - Map> errorDetailsMap = srFacilityIdValidator.validate(request); - assertEquals(errorDetailsMap.size(), 1); - } - - @Test - @DisplayName("should not add stock reconciliation to error details if facility id found") - void shouldAddStockReconciliationToErrorDetailsIfFacilityIdFound() { - StockReconciliationBulkRequest request = StockReconciliationBulkRequestTestBuilder.builder() - .withStock().withRequestInfo().build(); - - mockSomeResponse(); - - Map> errorDetailsMap = srFacilityIdValidator.validate(request); - assertEquals(errorDetailsMap.size(), 0); - } -} diff --git a/health-services/stock/src/test/java/org/egov/stock/validator/NonExistentEntityValidatorTest.java b/health-services/stock/src/test/java/org/egov/stock/validator/NonExistentEntityValidatorTest.java index 347f8e80ab2..cd21056b9c3 100644 --- a/health-services/stock/src/test/java/org/egov/stock/validator/NonExistentEntityValidatorTest.java +++ b/health-services/stock/src/test/java/org/egov/stock/validator/NonExistentEntityValidatorTest.java @@ -1,5 +1,11 @@ package org.egov.stock.validator; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.models.Error; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockBulkRequest; @@ -13,6 +19,7 @@ import org.egov.stock.repository.StockRepository; import org.egov.stock.validator.stock.SNonExistentValidator; import org.egov.stock.validator.stockreconciliation.SrNonExistentValidator; +import org.egov.tracer.model.CustomException; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -20,17 +27,12 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Collections; -import java.util.List; -import java.util.Map; - import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyList; -import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) +@Slf4j class NonExistentEntityValidatorTest { @InjectMocks @@ -49,8 +51,13 @@ class NonExistentEntityValidatorTest { @DisplayName("should add to error details map if entity not found") void shouldAddToErrorDetailsMapIfEntityNotFound() { StockBulkRequest request = StockBulkRequestTestBuilder.builder().withStockId("some-id").withRequestInfo().build(); - when(stockRepository.findById(anyList(), anyBoolean(), anyString())) - .thenReturn(Collections.emptyList()); + try { + when(stockRepository.find(any(), any(), any(), any(), any(), any(Boolean.class))) + .thenReturn(Collections.emptyList()); + } catch (QueryBuilderException e) { + log.error("Search failed for Stock with error: {}", e.getMessage(), e); + throw new CustomException("STOCK_SEARCH_FAILED", "Search Failed for Stock, " + e.getMessage()); + } Map> errorDetailsMap = stockNonExistentValidator.validate(request); @@ -61,8 +68,13 @@ void shouldAddToErrorDetailsMapIfEntityNotFound() { @DisplayName("should not add to error details map if entity found") void shouldNotAddToErrorDetailsMapIfEntityFound() { StockBulkRequest request = StockBulkRequestTestBuilder.builder().withStockId("some-id").withRequestInfo().build(); - when(stockRepository.findById(anyList(), anyBoolean(), anyString())) - .thenReturn(Collections.singletonList(StockTestBuilder.builder().withStock().withId("some-id").build())); + try { + when(stockRepository.find(any(), any(), any(), any(), any(), any(Boolean.class))) + .thenReturn(Collections.singletonList(StockTestBuilder.builder().withStock().withId("some-id").build())); + } catch (QueryBuilderException e) { + log.error("Search failed for Stock with error: {}", e.getMessage(), e); + throw new CustomException("STOCK_SEARCH_FAILED", "Search Failed for Stock, " + e.getMessage()); + } Map> errorDetailsMap = stockNonExistentValidator.validate(request); @@ -75,8 +87,13 @@ void shouldNotAddToErrorDetailsMapIfEntityFound() { void shouldAddToErrorDetailsMapIfReconciliationEntityNotFound() { StockReconciliationBulkRequest request = StockReconciliationBulkRequestTestBuilder.builder() .withStockId("some-id").withRequestInfo().build(); - when(stockReconciliationRepository.findById(anyList(), anyBoolean(), anyString())) + try { + when(stockReconciliationRepository.find(any(), any(), any(), any(), any(), any(Boolean.class))) .thenReturn(Collections.emptyList()); + } catch (QueryBuilderException e) { + log.error("Search failed for StockReconciliation with error: {}", e.getMessage(), e); + throw new CustomException("STOCK_RECONCILIANTION_SEARCH_FAILED", "Search Failed for StockReconciliation, " + e.getMessage()); + } Map> errorDetailsMap = stockReconciliationNonExistentValidator.validate(request); @@ -88,9 +105,14 @@ void shouldAddToErrorDetailsMapIfReconciliationEntityNotFound() { void shouldNotAddToErrorDetailsMapIfReconciliationEntityFound() { StockReconciliationBulkRequest request = StockReconciliationBulkRequestTestBuilder.builder() .withStockId("some-id").withRequestInfo().build(); - when(stockReconciliationRepository.findById(anyList(), anyBoolean(), anyString())) - .thenReturn(Collections.singletonList(StockReconciliationTestBuilder.builder().withStock() - .withId("some-id").build())); + try { + when(stockReconciliationRepository.find(any(), any(), any(), any(), any(), any(Boolean.class))) + .thenReturn(Collections.singletonList(StockReconciliationTestBuilder.builder().withStock() + .withId("some-id").build())); + } catch (QueryBuilderException e) { + log.error("Search failed for StockReconciliation with error: {}", e.getMessage(), e); + throw new CustomException("STOCK_RECONCILIANTION_SEARCH_FAILED", "Search Failed for StockReconciliation, " + e.getMessage()); + } Map> errorDetailsMap = stockReconciliationNonExistentValidator.validate(request); diff --git a/health-services/stock/src/test/java/org/egov/stock/validator/ReferenceIdValidatorTest.java b/health-services/stock/src/test/java/org/egov/stock/validator/ReferenceIdValidatorTest.java index 096a1ffd9e6..d1a19f6df06 100644 --- a/health-services/stock/src/test/java/org/egov/stock/validator/ReferenceIdValidatorTest.java +++ b/health-services/stock/src/test/java/org/egov/stock/validator/ReferenceIdValidatorTest.java @@ -1,6 +1,16 @@ package org.egov.stock.validator; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.assertj.core.util.Arrays; import org.egov.common.contract.request.RequestInfo; import org.egov.common.models.Error; import org.egov.common.models.stock.Stock; @@ -19,14 +29,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) class ReferenceIdValidatorTest { @@ -43,14 +45,18 @@ private void mockEmptyResponse() { when(facilityService.validateProjectFacilityMappings(any(List.class), any(String.class), any(Map.class), - any(RequestInfo.class))).thenReturn(Collections.emptyList()); + any(RequestInfo.class))).thenReturn(Collections.emptyMap()); } private void mockSomeResponse() { + + List facilityIds = new ArrayList<>(); + facilityIds.add("sender-id"); + when(facilityService.validateProjectFacilityMappings(any(List.class), any(String.class), any(Map.class), - any(RequestInfo.class))).thenReturn(Collections.singletonList("facility-id||reference-id")); + any(RequestInfo.class))).thenReturn(Collections.singletonMap("reference-id", facilityIds)); } @Test diff --git a/health-services/stock/src/test/java/org/egov/stock/validator/TransactingPartyIdValidatorTest.java b/health-services/stock/src/test/java/org/egov/stock/validator/TransactingPartyIdValidatorTest.java deleted file mode 100644 index 0eda35fe11a..00000000000 --- a/health-services/stock/src/test/java/org/egov/stock/validator/TransactingPartyIdValidatorTest.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.egov.stock.validator; - - -import org.egov.common.contract.request.RequestInfo; -import org.egov.common.models.Error; -import org.egov.common.models.stock.Stock; -import org.egov.common.models.stock.StockBulkRequest; -import org.egov.stock.helper.StockBulkRequestTestBuilder; -import org.egov.stock.service.FacilityService; -import org.egov.stock.validator.stock.STransactingPartyIdValidator; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -class TransactingPartyIdValidatorTest { - - @InjectMocks - private STransactingPartyIdValidator sTransactingPartyIdValidator; - - @Mock - private FacilityService facilityService; - - private void mockEmptyResponse() { - when(facilityService.validateFacilityIds(any(List.class), - any(List.class), - any(String.class), - any(Map.class), - any(RequestInfo.class))).thenReturn(Collections.emptyList()); - } - - private void mockSomeResponse() { - when(facilityService.validateFacilityIds(any(List.class), - any(List.class), - any(String.class), - any(Map.class), - any(RequestInfo.class))).thenReturn(Collections.singletonList("transaction-party-id")); - } - - @Test - @DisplayName("should add stock to error details if transacting party id not found") - void shouldAddStockToErrorDetailsIfTransactingPartyIdNotFound() { - StockBulkRequest request = StockBulkRequestTestBuilder.builder().withStock().withRequestInfo().build(); - - mockEmptyResponse(); - - Map> errorDetailsMap = sTransactingPartyIdValidator.validate(request); - assertEquals(errorDetailsMap.size(), 1); - } - - @Test - @DisplayName("should not add stock to error details if transacting party id found") - void shouldAddStockToErrorDetailsIfTransactingPartyIdFound() { - StockBulkRequest request = StockBulkRequestTestBuilder.builder().withStock().withRequestInfo().build(); - - mockSomeResponse(); - - Map> errorDetailsMap = sTransactingPartyIdValidator.validate(request); - assertEquals(errorDetailsMap.size(), 0); - } -} diff --git a/health-services/transformer/CHANGELOG.md b/health-services/transformer/CHANGELOG.md index a27826b5875..50427336512 100644 --- a/health-services/transformer/CHANGELOG.md +++ b/health-services/transformer/CHANGELOG.md @@ -1,5 +1,17 @@ All notable changes to this module will be documented in this file. +## 1.1.2 - 2024-05-29 +- Integrated Core 2.9LTS +- Upgraded to health models 1.0.20 and health common 1.0.16 +- Boundary v2 Integration +- MDMS v2 integration +- Upgraded PostgresSQL Driver version to 42.7.1 + +## 1.1.1 - 2024-05-10 +- Integrated Boundary v2 functionality + ## 1.0.0 -- Base version \ No newline at end of file +- Base version + +## 1.1.0 diff --git a/health-services/transformer/pom.xml b/health-services/transformer/pom.xml index ba2b21ef154..7a94fd3e47c 100644 --- a/health-services/transformer/pom.xml +++ b/health-services/transformer/pom.xml @@ -5,16 +5,17 @@ transformer jar transformer - 1.0.0 + 1.1.2 - 1.8 + 17 ${java.version} ${java.version} + 1.18.22 org.springframework.boot spring-boot-starter-parent - 2.2.6.RELEASE + 3.2.2 src/main/java @@ -46,6 +47,7 @@ org.projectlombok lombok + ${lombok.version} true @@ -57,22 +59,34 @@ org.egov.common health-services-models - 1.0.0-SNAPSHOT + 1.0.20-SNAPSHOT + compile + + + org.egov.common + health-services-common + 1.0.17-SNAPSHOT compile org.egov.services tracer - 2.1.4-SNAPSHOT + 2.9.0-SNAPSHOT - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 + org.postgresql + postgresql + 42.7.1 + + + junit + junit + 4.13.2 + test - - javax.validation - validation-api + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 diff --git a/health-services/transformer/src/main/java/org/egov/transformer/boundary/BoundaryMapper.java b/health-services/transformer/src/main/java/org/egov/transformer/boundary/BoundaryMapper.java index b9b0f2b0ee3..e6fbfbd4eb8 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/boundary/BoundaryMapper.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/boundary/BoundaryMapper.java @@ -1,17 +1,16 @@ package org.egov.transformer.boundary; -import org.egov.common.models.transformer.upstream.Boundary; +import org.egov.common.models.core.Boundary; public class BoundaryMapper { public static BoundaryNode from(Boundary boundary) { return BoundaryNode.builder() - .name(boundary.getName()) + .id(boundary.getId()) .code(boundary.getCode()) - .label(boundary.getLabel()) - .latitude(boundary.getLatitude()) - .longitude(boundary.getLongitude()) + .tenantId(boundary.getTenantId()) + .geometry(boundary.getGeometry()) .build(); } diff --git a/health-services/transformer/src/main/java/org/egov/transformer/boundary/BoundaryNode.java b/health-services/transformer/src/main/java/org/egov/transformer/boundary/BoundaryNode.java index f9189e869a1..72e14c5b9ed 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/boundary/BoundaryNode.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/boundary/BoundaryNode.java @@ -1,5 +1,6 @@ package org.egov.transformer.boundary; +import com.fasterxml.jackson.databind.JsonNode; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -10,9 +11,8 @@ @NoArgsConstructor @Builder public class BoundaryNode { + private String id; + private String tenantId; private String code; - private String name; - private String label; - private String latitude; - private String longitude; + private JsonNode geometry; } diff --git a/health-services/transformer/src/main/java/org/egov/transformer/boundary/TreeGenerator.java b/health-services/transformer/src/main/java/org/egov/transformer/boundary/TreeGenerator.java deleted file mode 100644 index 4a96ed10f95..00000000000 --- a/health-services/transformer/src/main/java/org/egov/transformer/boundary/TreeGenerator.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.egov.transformer.boundary; - - -import org.egov.common.models.transformer.upstream.Boundary; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.List; - -@Component -public class TreeGenerator { - - - public BoundaryTree generateTree(Boundary boundary) { - BoundaryTree boundaryTree = new BoundaryTree(); - boundaryTree.setBoundaryNode(BoundaryMapper.from(boundary)); - if (boundary.getChildren() != null && !boundary.getChildren().isEmpty()) { - List boundaryTrees = new ArrayList<>(); - boundaryTree.setBoundaryTrees(boundaryTrees); - for (Boundary child : boundary.getChildren()) { - BoundaryTree resultTree = generateTree(child); - resultTree.setParent(boundaryTree); - boundaryTrees.add(resultTree); - } - } - return boundaryTree; - } - - public BoundaryTree search(BoundaryTree boundaryTree, String code) { - if (code.equals(boundaryTree.getBoundaryNode().getCode())) { - return boundaryTree; - } - BoundaryTree bt = null; - if (boundaryTree.getBoundaryTrees() != null && !boundaryTree.getBoundaryTrees().isEmpty()) { - for (BoundaryTree child : boundaryTree.getBoundaryTrees()) { - bt = search(child, code); - if (bt != null) { - break; - } - } - } - return bt; - } -} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java b/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java index b699d3f942c..050c1ea7217 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java @@ -1,5 +1,10 @@ package org.egov.transformer.config; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; +import java.util.stream.Collectors; + import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.PropertyAccessor; @@ -7,6 +12,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import jakarta.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.project.Project; import org.egov.common.models.project.ProjectStaff; @@ -14,6 +20,7 @@ import org.egov.common.models.stock.Stock; import org.egov.tracer.config.TracerConfiguration; import org.egov.transformer.enums.Operation; +import org.egov.transformer.models.upstream.Service; import org.egov.transformer.service.TransformationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -22,14 +29,14 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.RedisStandaloneConfiguration; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import javax.annotation.PostConstruct; -import java.util.List; -import java.util.Map; -import java.util.TimeZone; -import java.util.stream.Collectors; - @Import({TracerConfiguration.class}) @Configuration @ComponentScan(basePackages = {"org.egov"}) @@ -39,6 +46,9 @@ public class MainConfiguration { @Value("${app.timezone}") private String timeZone; + @Value("${spring.redis.host}") + private String redisHost; + @PostConstruct public void initialize() { TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); @@ -118,4 +128,37 @@ public Map>> getOperationTransforma log.info(map.toString()); return map; } + @Bean + @Autowired + @Qualifier("serviceTaskTransformationServiceMap") + public Map>> getOperationTransformationServiceMapForServiceTask( + List> transformationServices) { + Map>> map = transformationServices + .stream() + .collect(Collectors.groupingBy(TransformationService::getOperation)); + log.info(map.toString()); + return map; + } + + @Bean + public RedisConnectionFactory redisConnectionFactory() { + RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(); + redisStandaloneConfiguration.setHostName(redisHost); + return new JedisConnectionFactory(redisStandaloneConfiguration); + } + + @Bean + public RedisTemplate redisTemplate(@Qualifier("redisObjectMapper") ObjectMapper redisObjectMapper, + RedisConnectionFactory redisConnectionFactory) { + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(redisObjectMapper, Object.class); + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(serializer); + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashValueSerializer(serializer); + redisTemplate.afterPropertiesSet(); + return redisTemplate; + } + } \ No newline at end of file diff --git a/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java b/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java index 3698ab4f6b5..1a577a98fb7 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java @@ -20,6 +20,9 @@ public class TransformerProperties { @Value("${transformer.producer.bulk.project.staff.index.v1.topic}") private String transformerProducerBulkProjectStaffIndexV1Topic; + @Value("${transformer.producer.service.task.index.v1.topic}") + private String transformerProducerServiceTaskIndexV1Topic; + @Value("${transformer.producer.bulk.project.index.v1.topic}") private String transformerProducerBulkProjectIndexV1Topic; @@ -44,6 +47,12 @@ public class TransformerProperties { @Value("${egov.search.facility.url}") private String facilitySearchUrl; + @Value("${egov.search.servicedefinition.url}") + private String serviceDefinitionSearchUrl; + + @Value("${egov.servicedefinition.host}") + private String serviceDefinitionHost; + @Value("${search.api.limit:100}") private String searchApiLimit; @@ -65,5 +74,16 @@ public class TransformerProperties { @Value("${boundary.label.name.administrativeProvince}") private String administrativeProvince; + @Value("${egov.boundary.host}") + private String boundaryServiceHost; + + @Value("${egov.boundary.search.url}") + private String boundarySearchUrl; + + @Value("${egov.boundary.relationship.search.url}") + private String boundaryRelationshipSearchUrl; + + @Value("${egov.boundary.hierarchy.name}") + private String boundaryHierarchyName; } diff --git a/health-services/transformer/src/main/java/org/egov/transformer/consumer/ServiceTaskConsumer.java b/health-services/transformer/src/main/java/org/egov/transformer/consumer/ServiceTaskConsumer.java new file mode 100644 index 00000000000..9f710b5a18e --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/consumer/ServiceTaskConsumer.java @@ -0,0 +1,48 @@ +package org.egov.transformer.consumer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.egov.transformer.enums.Operation; +import org.egov.transformer.handler.TransformationHandler; +import org.egov.transformer.models.upstream.Service; +import org.egov.transformer.models.upstream.ServiceRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@Component +@Slf4j +public class ServiceTaskConsumer { + private final TransformationHandler transformationHandler; + + private final ObjectMapper objectMapper; + + @Autowired + public ServiceTaskConsumer(TransformationHandler transformationHandler, + @Qualifier("objectMapper") ObjectMapper objectMapper) { + this.transformationHandler = transformationHandler; + this.objectMapper = objectMapper; + } + + @KafkaListener(topics = {"${transformer.consumer.create.service.topic}"}) + public void consumeServiceTask(ConsumerRecord payload, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + List payloadList = Arrays.asList(objectMapper + .readValue((String) payload.value(), ServiceRequest.class)); + List collect = payloadList.stream().map(p -> p.getService()).collect(Collectors.toList()); + transformationHandler.handle(collect, Operation.SERVICE); + } catch (Exception exception) { + log.error("error in service task consumer", exception); + } + } + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/enums/Operation.java b/health-services/transformer/src/main/java/org/egov/transformer/enums/Operation.java index 86a517f17f3..32b8b7d878e 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/enums/Operation.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/enums/Operation.java @@ -7,7 +7,8 @@ public enum Operation { TASK("TASK"), PROJECT_STAFF("PROJECT_STAFF"), PROJECT("PROJECT"), - STOCK("STOCK"); + STOCK("STOCK"), + SERVICE("SERVICE"); private String value; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/handler/ServiceTaskTransformationHandler.java b/health-services/transformer/src/main/java/org/egov/transformer/handler/ServiceTaskTransformationHandler.java new file mode 100644 index 00000000000..ec312b14498 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/handler/ServiceTaskTransformationHandler.java @@ -0,0 +1,31 @@ +package org.egov.transformer.handler; + +import org.egov.transformer.enums.Operation; +import org.egov.transformer.models.upstream.Service; +import org.egov.transformer.service.TransformationService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +@Component +public class ServiceTaskTransformationHandler implements TransformationHandler{ + private final Map>> operationTransformationServiceMap; + + @Autowired + public ServiceTaskTransformationHandler(@Qualifier("serviceTaskTransformationServiceMap") + Map>> operationTransformationServiceMap) { + this.operationTransformationServiceMap = operationTransformationServiceMap; + } + + @Override + public void handle(List payloadList, Operation operation) { + operationTransformationServiceMap.entrySet().stream() + .filter(e -> e.getKey().equals(operation)) + .map(Map.Entry::getValue) + .flatMap(Collection::stream).forEach(es -> es.transform(payloadList)); + } +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/http/client/ServiceRequestClient.java b/health-services/transformer/src/main/java/org/egov/transformer/http/client/ServiceRequestClient.java index edde27c1486..b3a36bcb10b 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/http/client/ServiceRequestClient.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/http/client/ServiceRequestClient.java @@ -11,7 +11,7 @@ import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; -@Repository +//@Repository @Slf4j public class ServiceRequestClient { diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundaryRequest.java b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundaryRequest.java new file mode 100644 index 00000000000..3e128bcd434 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundaryRequest.java @@ -0,0 +1,38 @@ +package org.egov.transformer.models.boundary; + +import java.util.List; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryRequest + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @Valid + @NotNull + @JsonProperty("Boundary") + @Size(min = 1, max = 300) + private List boundary = null; + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundaryResponse.java b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundaryResponse.java new file mode 100644 index 00000000000..afcdfa94736 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundaryResponse.java @@ -0,0 +1,44 @@ +package org.egov.transformer.models.boundary; + +import java.util.ArrayList; +import java.util.List; +import jakarta.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryResponse + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Boundary") + @Valid + private List boundary = null; + + + public BoundaryResponse addBoundaryItem(Boundary boundaryItem) { + if (this.boundary == null) { + this.boundary = new ArrayList<>(); + } + this.boundary.add(boundaryItem); + return this; + } + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundarySearchCriteria.java b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundarySearchCriteria.java new file mode 100644 index 00000000000..cfcd2c81732 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundarySearchCriteria.java @@ -0,0 +1,37 @@ +package org.egov.transformer.models.boundary; + +import java.util.List; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundarySearchCriteria { + + @NotNull + @Size(min = 1) + @JsonProperty("codes") + private List codes; + + @NotNull + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundarySearchResponse.java b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundarySearchResponse.java new file mode 100644 index 00000000000..244af7e5a27 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundarySearchResponse.java @@ -0,0 +1,33 @@ +package org.egov.transformer.models.boundary; + +import java.util.List; +import jakarta.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +/** + * BoundarySearchResponse + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundarySearchResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("TenantBoundary") + @Valid + private List tenantBoundary = null; + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/EnrichedBoundary.java b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/EnrichedBoundary.java new file mode 100644 index 00000000000..8b85a96e3a5 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/EnrichedBoundary.java @@ -0,0 +1,43 @@ +package org.egov.transformer.models.boundary; + +import java.util.List; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * EnrichedBoundary + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class EnrichedBoundary { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("code") + @NotNull + private String code = null; + + @JsonProperty("boundaryType") + private String boundaryType = null; + + @JsonProperty("children") + @Valid + private List children = null; + + @JsonIgnore + private String parent = null; + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/HierarchyRelation.java b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/HierarchyRelation.java new file mode 100644 index 00000000000..b1faf8f5f98 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/HierarchyRelation.java @@ -0,0 +1,34 @@ +package org.egov.transformer.models.boundary; + +import java.util.List; +import jakarta.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * HierarchyRelation + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class HierarchyRelation { + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("hierarchyType") + private String hierarchyType = null; + + @JsonProperty("boundary") + @Valid + private List boundary = null; + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java index 4fe8a095493..6e504ad3ec7 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java @@ -28,7 +28,7 @@ public class ProjectTaskIndexV1 { @JsonProperty("productVariant") private String productVariant; @JsonProperty("quantity") - private Long quantity; + private Double quantity; @JsonProperty("deliveredTo") private String deliveredTo; @JsonProperty("isDelivered") @@ -57,4 +57,6 @@ public class ProjectTaskIndexV1 { private Long createdTime; @JsonProperty("lastModifiedTime") private Long lastModifiedTime; + @JsonProperty("isDeleted") + private boolean isDeleted; } diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ServiceIndexV1.java b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ServiceIndexV1.java new file mode 100644 index 00000000000..55f38bc837a --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ServiceIndexV1.java @@ -0,0 +1,44 @@ +package org.egov.transformer.models.downstream; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.transformer.models.upstream.AttributeValue; + +import java.util.ArrayList; +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ServiceIndexV1 { + @JsonProperty("id") + private String id; + @JsonProperty("createdTime") + private Long createdTime; + @JsonProperty("createdBy") + private String createdBy; + @JsonProperty("supervisorLevel") + private String supervisorLevel; + @JsonProperty("checklistName") + private String checklistName; + @JsonProperty("projectId") + private String projectId; + @JsonProperty("serviceDefinitionId") + private String serviceDefinitionId; + @JsonProperty("province") + private String province; + @JsonProperty("district") + private String district; + @JsonProperty("tenantId") + private String tenantId; + @JsonProperty("userId") + private String userId; + @JsonProperty("attributes") + private List attributes = new ArrayList<>(); +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/StockIndexV1.java b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/StockIndexV1.java index b43eea1c3e3..060cd3bf659 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/StockIndexV1.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/StockIndexV1.java @@ -23,6 +23,9 @@ public class StockIndexV1 { @JsonProperty("facilityId") private String facilityId; + @JsonProperty("facilityName") + private String facilityName; + @JsonProperty("productVariant") private String productVariant; @@ -38,6 +41,9 @@ public class StockIndexV1 { @JsonProperty("eventTimeStamp") private Long eventTimeStamp; + @JsonProperty("dateOfEntry") + private Long dateOfEntry; + @JsonProperty("province") private String province; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeDefinition.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeDefinition.java new file mode 100644 index 00000000000..665c8f91f5a --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeDefinition.java @@ -0,0 +1,112 @@ +package org.egov.transformer.models.upstream; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import digit.models.coremodels.AuditDetails; +import 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; + +/** + * Hold the attribute definition fields details as json object. + */ + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AttributeDefinition { + @JsonProperty("id") + private String id = null; + + @JsonProperty("referenceId") + private String referenceId = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("code") + private String code = null; + + /** + * defines the attribute type + */ + public enum DataTypeEnum { + STRING("String"), + + NUMBER("Number"), + + TEXT("Text"), + + DATETIME("Datetime"), + + SINGLEVALUELIST("SingleValueList"), + + MULTIVALUELIST("MultiValueList"), + + FILE("File"); + + private String value; + + DataTypeEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static DataTypeEnum fromValue(String text) { + for (DataTypeEnum b : DataTypeEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + + @JsonProperty("dataType") + private DataTypeEnum dataType = null; + + @JsonProperty("values") + private List values = null; + + @JsonProperty("isActive") + private Boolean isActive = true; + + @JsonProperty("required") + private Boolean required = null; + + @JsonProperty("regex") + private String regex = null; + + @JsonProperty("order") + private String order = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + + public AttributeDefinition addValuesItem(String valuesItem) { + if (this.values == null) { + this.values = new ArrayList<>(); + } + this.values.add(valuesItem); + return this; + } + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeValue.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeValue.java new file mode 100644 index 00000000000..6f69634df23 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeValue.java @@ -0,0 +1,37 @@ +package org.egov.transformer.models.upstream; + +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * Hold the attribute details as object. + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AttributeValue { + @JsonProperty("id") + private String id = null; + + @JsonProperty("referenceId") + private String referenceId = null; + + @JsonProperty("attributeCode") + private String attributeCode = null; + + @JsonProperty("value") + private Object value = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Pagination.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Pagination.java new file mode 100644 index 00000000000..806daa44f15 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Pagination.java @@ -0,0 +1,68 @@ +package org.egov.transformer.models.upstream; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * Pagination details + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Pagination { + @JsonProperty("limit") + private Integer limit = new Integer(10); + + @JsonProperty("offset") + private Integer offset = new Integer(0); + + @JsonProperty("totalCount") + private Long totalCount = null; + + @JsonProperty("sortBy") + private String sortBy = null; + + /** + * Sorting order + */ + public enum OrderEnum { + ASC("asc"), + + DESC("desc"); + + private String value; + + OrderEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static OrderEnum fromValue(String text) { + for (OrderEnum b : OrderEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + + @JsonProperty("order") + private OrderEnum order = null; + + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Service.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Service.java new file mode 100644 index 00000000000..59a9b1a5be7 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Service.java @@ -0,0 +1,57 @@ +package org.egov.transformer.models.upstream; + +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.List; + +/** + * Hold the Service field details as json object. + */ + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Service { + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("serviceDefId") + private String serviceDefId = null; + + @JsonProperty("referenceId") + private String referenceId = null; + + @JsonProperty("attributes") + private List attributes = new ArrayList<>(); + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("accountId") + private String accountId = null; + + @JsonProperty("clientId") + private String clientId = null; + + + public Service addAttributesItem(AttributeValue attributesItem) { + this.attributes.add(attributesItem); + return this; + } + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinition.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinition.java new file mode 100644 index 00000000000..a1fee705612 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinition.java @@ -0,0 +1,54 @@ +package org.egov.transformer.models.upstream; + +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.List; + +/** + * Holds the Service Definition details json object. + */ + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ServiceDefinition { + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("code") + private String code = null; + + @JsonProperty("isActive") + private Boolean isActive = true; + + @JsonProperty("attributes") + private List attributes = new ArrayList<>(); + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("clientId") + private String clientId = null; + + + public ServiceDefinition addAttributesItem(AttributeDefinition attributesItem) { + this.attributes.add(attributesItem); + return this; + } + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionCriteria.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionCriteria.java new file mode 100644 index 00000000000..fda0f1c7369 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionCriteria.java @@ -0,0 +1,51 @@ +package org.egov.transformer.models.upstream; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.List; + +/** + * The object will contain all the search parameters for Service Definition. + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ServiceDefinitionCriteria { + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("ids") + private List ids = null; + + @JsonProperty("code") + private List code = null; + + @JsonProperty("clientId") + private String clientId = null; + + + public ServiceDefinitionCriteria addIdsItem(String idsItem) { + if (this.ids == null) { + this.ids = new ArrayList<>(); + } + this.ids.add(idsItem); + return this; + } + + public ServiceDefinitionCriteria addCodeItem(String codeItem) { + if (this.code == null) { + this.code = new ArrayList<>(); + } + this.code.add(codeItem); + return this; + } + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionResponse.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionResponse.java new file mode 100644 index 00000000000..d2ffe04cc25 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionResponse.java @@ -0,0 +1,41 @@ +package org.egov.transformer.models.upstream; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.List; + +/** + * ServiceDefinitionResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ServiceDefinitionResponse { + @JsonProperty("ResponseInfo") + private ResponseInfo responseInfo = null; + + @JsonProperty("ServiceDefinitions") + private List serviceDefinition = null; + + @JsonProperty("Pagination") + private Pagination pagination = null; + + + public ServiceDefinitionResponse addServiceDefinitionItem(ServiceDefinition serviceDefinitionItem) { + if (this.serviceDefinition == null) { + this.serviceDefinition = new ArrayList<>(); + } + this.serviceDefinition.add(serviceDefinitionItem); + return this; + } + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionSearchRequest.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionSearchRequest.java new file mode 100644 index 00000000000..ec3fc65dbe3 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionSearchRequest.java @@ -0,0 +1,28 @@ +package org.egov.transformer.models.upstream; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * ServiceDefinitionSearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ServiceDefinitionSearchRequest { + @JsonProperty("RequestInfo") + private RequestInfo requestInfo = null; + + @JsonProperty("ServiceDefinitionCriteria") + private ServiceDefinitionCriteria serviceDefinitionCriteria = null; + + @JsonProperty("Pagination") + private Pagination pagination = null; +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceRequest.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceRequest.java new file mode 100644 index 00000000000..e259cdc1a51 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceRequest.java @@ -0,0 +1,25 @@ +package org.egov.transformer.models.upstream; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * ServiceRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ServiceRequest { + @JsonProperty("RequestInfo") + private RequestInfo requestInfo = null; + + @JsonProperty("Service") + private Service service = null; +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/producer/Producer.java b/health-services/transformer/src/main/java/org/egov/transformer/producer/Producer.java index 009ccc4c089..0d5eef066df 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/producer/Producer.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/producer/Producer.java @@ -7,7 +7,7 @@ // NOTE: If tracer is disabled change CustomKafkaTemplate to KafkaTemplate in autowiring -@Service + @Slf4j public class Producer { diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/BoundaryService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/BoundaryService.java deleted file mode 100644 index 61591ce91c2..00000000000 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/BoundaryService.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.egov.transformer.service; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.jayway.jsonpath.Configuration; -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -import com.jayway.jsonpath.Option; -import lombok.extern.slf4j.Slf4j; -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import org.egov.common.contract.request.RequestInfo; -import org.egov.common.models.transformer.upstream.Boundary; -import org.egov.tracer.model.CustomException; -import org.egov.transformer.boundary.BoundaryTree; -import org.egov.transformer.boundary.TreeGenerator; -import org.egov.transformer.config.TransformerProperties; -import org.egov.transformer.http.client.ServiceRequestClient; -import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; - -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -@Component -@Slf4j -public class BoundaryService { - - private final TransformerProperties transformerProperties; - - private final ServiceRequestClient serviceRequestClient; - - private final ObjectMapper objectMapper; - - private final TreeGenerator treeGenerator; - - private static final Map> boundaryListMap = new ConcurrentHashMap<>(); - - public BoundaryService(TransformerProperties transformerProperties, - ServiceRequestClient serviceRequestClient, - ObjectMapper objectMapper, TreeGenerator treeGenerator) { - this.transformerProperties = transformerProperties; - this.serviceRequestClient = serviceRequestClient; - this.objectMapper = objectMapper; - this.treeGenerator = treeGenerator; - } - - public List getBoundary(String code, String hierarchyTypeCode, String tenantId) { - if (boundaryListMap.containsKey(code)) { - log.info("getting boudary data for code {} from cache", code); - return boundaryListMap.get(code); - } - List boundaryList = searchBoundary(code, hierarchyTypeCode, tenantId); - if (!boundaryList.isEmpty()) { - boundaryListMap.put(code, boundaryList); - } else { - boundaryList = Collections.emptyList(); - } - return boundaryList; - } - - public BoundaryTree generateTree(Boundary boundary) { - return treeGenerator.generateTree(boundary); - } - - public BoundaryTree search(BoundaryTree boundaryTree, String code) { - return treeGenerator.search(boundaryTree, code); - } - - private List searchBoundary(String code, String hierarchyTypeCode, String tenantId) { - - LinkedHashMap response; - try { - StringBuilder uri = new StringBuilder(); - uri.append(transformerProperties.getLocationHost()) - .append(transformerProperties.getLocationSearchUrl()) - .append("?limit=").append(transformerProperties.getSearchApiLimit()) - .append("&offset=0") - .append("&tenantId=").append(tenantId); - if (hierarchyTypeCode != null) { - uri.append("&hierarchyTypeCode=").append(hierarchyTypeCode); - } - uri.append("&code=").append(code); - response = serviceRequestClient.fetchResult(uri, - RequestInfo.builder().build(), - LinkedHashMap.class); - } catch (Exception e) { - log.error("error while calling boundary service", e); - throw new CustomException("BOUNDARY_ERROR", "error while calling boundary service"); - } - if (response != null) { - if (CollectionUtils.isEmpty(response)) { - log.error("empty response received from boundary service"); - throw new CustomException("BOUNDARY_ERROR", "the response from location service is empty or null"); - } - Configuration cf = Configuration.builder().options(Option.ALWAYS_RETURN_LIST).build(); - String jsonString = new JSONObject(response).toString(); - DocumentContext context = JsonPath.using(cf).parse(jsonString); - JSONArray jsonArray = context.read("$.TenantBoundary[?(@.hierarchyType.code == 'ADMIN')].boundary"); - if (jsonArray != null) { - String str = jsonArray.get(0).toString(); - try { - return Arrays.asList(objectMapper - .readValue(str, - Boundary[].class)); - } catch (JsonProcessingException e) { - log.error("error in paring json", e); - throw new CustomException("JSON_ERROR", "error in parsing json"); - } - } - log.warn("boundary list is empty"); - } - return Collections.emptyList(); - } -} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/FacilityService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/FacilityService.java index 17caf3ec5da..91f8a4aa68c 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/FacilityService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/FacilityService.java @@ -1,5 +1,11 @@ package org.egov.transformer.service; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; @@ -9,15 +15,9 @@ import org.egov.common.models.facility.FacilitySearch; import org.egov.common.models.facility.FacilitySearchRequest; import org.egov.transformer.config.TransformerProperties; -import org.egov.transformer.http.client.ServiceRequestClient; +import org.egov.common.http.client.ServiceRequestClient; import org.springframework.stereotype.Service; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - @Service @Slf4j public class FacilityService { diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/MdmsService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/MdmsService.java index 7599cd82242..f29309f74de 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/MdmsService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/MdmsService.java @@ -2,7 +2,7 @@ import lombok.extern.slf4j.Slf4j; import org.egov.tracer.model.CustomException; -import org.egov.transformer.http.client.ServiceRequestClient; +import org.egov.common.http.client.ServiceRequestClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectIndexV1TransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectIndexV1TransformationService.java index 674d2ccdbe6..62b453eaf66 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectIndexV1TransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectIndexV1TransformationService.java @@ -3,7 +3,7 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.project.Project; import org.egov.transformer.config.TransformerProperties; -import org.egov.transformer.producer.Producer; +import org.egov.common.producer.Producer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java index f16485605c4..c0970a51a6d 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java @@ -1,5 +1,15 @@ package org.egov.transformer.service; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Deque; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -13,20 +23,13 @@ import org.egov.common.models.project.Project; import org.egov.common.models.project.ProjectRequest; import org.egov.common.models.project.ProjectResponse; -import org.egov.common.models.transformer.upstream.Boundary; import org.egov.tracer.model.CustomException; -import org.egov.transformer.boundary.BoundaryNode; -import org.egov.transformer.boundary.BoundaryTree; import org.egov.transformer.config.TransformerProperties; -import org.egov.transformer.http.client.ServiceRequestClient; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.transformer.models.boundary.BoundarySearchResponse; +import org.egov.transformer.models.boundary.EnrichedBoundary; import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; +import org.springframework.util.CollectionUtils; import static org.egov.transformer.Constants.INTERNAL_SERVER_ERROR; import static org.egov.transformer.Constants.MDMS_RESPONSE; @@ -42,19 +45,16 @@ public class ProjectService { private final ObjectMapper objectMapper; - private final BoundaryService boundaryService; - private final MdmsService mdmsService; private static final Map projectMap = new ConcurrentHashMap<>(); public ProjectService(TransformerProperties transformerProperties, ServiceRequestClient serviceRequestClient, - ObjectMapper objectMapper, BoundaryService boundaryService, MdmsService mdmsService) { + ObjectMapper objectMapper, MdmsService mdmsService) { this.transformerProperties = transformerProperties; this.serviceRequestClient = serviceRequestClient; this.objectMapper = objectMapper; - this.boundaryService = boundaryService; this.mdmsService = mdmsService; } @@ -77,22 +77,120 @@ public Project getProject(String projectId, String tenantId) { return project; } - public Map getBoundaryLabelToNameMap(String projectId, String tenantId) { + public Project getProjectByName(String projectName, String tenantId) { + if (projectMap.containsKey(projectName)) { + log.info("getting project {} from cache", projectName); + return projectMap.get(projectName); + } + List projects = searchProjectByName(projectName, tenantId); + Project project = null; + if (!projects.isEmpty()) { + project = projects.get(0); + projectMap.put(projectName, project); + } + return project; + } + + public Map getBoundaryCodeToNameMapByProjectId(String projectId, String tenantId) { Project project = getProject(projectId, tenantId); String locationCode = project.getAddress().getBoundary(); - return getBoundaryLabelToNameMap(project, locationCode); + return getBoundaryCodeToNameMap(locationCode, tenantId); + } + + public Map getBoundaryCodeToNameMap(String locationCode, String tenantId) { + List boundaries = new ArrayList<>(); + try { + // Fetch boundary details from the service + log.debug("Fetching boundary relation details for tenantId: {}, boundary: {}", tenantId, locationCode); + BoundarySearchResponse boundarySearchResponse = serviceRequestClient.fetchResult( + new StringBuilder(transformerProperties.getBoundaryServiceHost() + + transformerProperties.getBoundaryRelationshipSearchUrl() + +"?includeParents=true&tenantId=" + tenantId + + "&hierarchyType=" + transformerProperties.getBoundaryHierarchyName() + + "&codes=" + locationCode), + RequestInfo.builder().build(), + BoundarySearchResponse.class + ); + log.debug("Boundary Relationship details fetched successfully for tenantId: {}", tenantId); + + List enrichedBoundaries = boundarySearchResponse.getTenantBoundary().stream() + .filter(hierarchyRelation -> !CollectionUtils.isEmpty(hierarchyRelation.getBoundary())) + .flatMap(hierarchyRelation -> hierarchyRelation.getBoundary().stream()) + .collect(Collectors.toList()); + + getAllBoundaryCodes(enrichedBoundaries, boundaries); + + } catch (Exception e) { + log.error("Exception while searching boundaries for tenantId: {}", tenantId, e); + // Throw a custom exception if an error occurs during boundary search + throw new CustomException("BOUNDARY_SERVICE_SEARCH_ERROR","Error in while fetching boundaries from Boundary Service : " + e.getMessage()); + } + + return boundaries.stream() + .collect(Collectors.toMap( + EnrichedBoundary::getBoundaryType, + boundary -> boundary.getCode().substring(boundary.getCode().lastIndexOf('_') + 1) + )); } - public Map getBoundaryLabelToNameMap(Project project, String locationCode) { - List boundaryList = boundaryService.getBoundary(locationCode, "ADMIN", - project.getTenantId()); - BoundaryTree boundaryTree = boundaryService.generateTree(boundaryList.get(0)); - BoundaryTree locationTree = boundaryService.search(boundaryTree, locationCode); - List parentNodes = locationTree.getParentNodes(); - Map resultMap = parentNodes.stream().collect(Collectors - .toMap(BoundaryNode::getLabel, BoundaryNode::getName)); - resultMap.put(locationTree.getBoundaryNode().getLabel(), locationTree.getBoundaryNode().getName()); - return resultMap; + private void getAllBoundaryCodes(List enrichedBoundaries, List boundaries) { + if (enrichedBoundaries == null || enrichedBoundaries.isEmpty()) { + return; + } + + for (EnrichedBoundary root : enrichedBoundaries) { + if (root != null) { + Deque stack = new ArrayDeque<>(); + stack.push(root); + + while (!stack.isEmpty()) { + EnrichedBoundary current = stack.pop(); + if (current != null) { + boundaries.add(current); + if (current.getChildren() != null) { + stack.addAll(current.getChildren()); + } + } + } + } + } + } + + + + private List searchProjectByName(String projectName, String tenantId) { + + ProjectRequest request = ProjectRequest.builder() + .requestInfo(RequestInfo.builder(). + userInfo(User.builder() + .uuid("transformer-uuid") + .build()) + .build()) + .projects(Collections.singletonList(Project.builder().name(projectName).tenantId(tenantId).build())) + .build(); + + try { + log.info(objectMapper.writeValueAsString(request)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + ProjectResponse response; + try { + StringBuilder uri = new StringBuilder(); + uri.append(transformerProperties.getProjectHost()) + .append(transformerProperties.getProjectSearchUrl()) + .append("?limit=").append(transformerProperties.getSearchApiLimit()) + .append("&offset=0") + .append("&tenantId=").append(tenantId); + response = serviceRequestClient.fetchResult(uri, + request, + ProjectResponse.class); + } catch (Exception e) { + log.error("error while fetching project list", e); + throw new CustomException("PROJECT_FETCH_ERROR", + "error while fetching project details for name: " + projectName); + } + return response.getProject(); } private List searchProject(String projectId, String tenantId) { diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffIndexV1TransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffIndexV1TransformationService.java index 199ef6d248c..b9f9f68109c 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffIndexV1TransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffIndexV1TransformationService.java @@ -3,7 +3,7 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.project.ProjectStaff; import org.egov.transformer.config.TransformerProperties; -import org.egov.transformer.producer.Producer; +import org.egov.common.producer.Producer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffTransformationService.java index 05c6e366ed3..d4966a6512f 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffTransformationService.java @@ -5,7 +5,7 @@ import org.egov.transformer.config.TransformerProperties; import org.egov.transformer.enums.Operation; import org.egov.transformer.models.downstream.ProjectStaffIndexV1; -import org.egov.transformer.producer.Producer; +import org.egov.common.producer.Producer; import org.egov.transformer.service.transformer.Transformer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -67,7 +67,7 @@ static class ProjectStaffIndexV1Transformer implements @Override public List transform(ProjectStaff projectStaff) { Map boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMap(projectStaff.getProjectId(), projectStaff.getTenantId()); + .getBoundaryCodeToNameMapByProjectId(projectStaff.getProjectId(), projectStaff.getTenantId()); log.info("boundary labels {}", boundaryLabelToNameMap.toString()); return Collections.singletonList(ProjectStaffIndexV1.builder() .id(projectStaff.getId()) diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskIndexV1TransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskIndexV1TransformationService.java index 4d94b935419..87b877472b9 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskIndexV1TransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskIndexV1TransformationService.java @@ -3,7 +3,7 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.project.Task; import org.egov.transformer.config.TransformerProperties; -import org.egov.transformer.producer.Producer; +import org.egov.common.producer.Producer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java index c4ec7c8318a..286b416649f 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java @@ -5,7 +5,7 @@ import org.egov.transformer.config.TransformerProperties; import org.egov.transformer.enums.Operation; import org.egov.transformer.models.downstream.ProjectTaskIndexV1; -import org.egov.transformer.producer.Producer; +import org.egov.common.producer.Producer; import org.egov.transformer.service.transformer.Transformer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -65,9 +65,16 @@ static class ProjectTaskIndexV1Transformer implements @Override public List transform(Task task) { - Map boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMap(task.getProjectId(), task.getTenantId()); + Map boundaryLabelToNameMap = null; + if (task.getAddress().getLocality() != null && task.getAddress().getLocality().getCode() != null) { + boundaryLabelToNameMap = projectService + .getBoundaryCodeToNameMap(task.getAddress().getLocality().getCode(), task.getTenantId()); + } else { + boundaryLabelToNameMap = projectService + .getBoundaryCodeToNameMapByProjectId(task.getProjectId(), task.getTenantId()); + } log.info("boundary labels {}", boundaryLabelToNameMap.toString()); + Map finalBoundaryLabelToNameMap = boundaryLabelToNameMap; return task.getResources().stream().map(r -> ProjectTaskIndexV1.builder() .id(r.getId()) @@ -81,17 +88,19 @@ public List transform(Task task) { .quantity(r.getQuantity()) .deliveredTo("HOUSEHOLD") .deliveryComments(r.getDeliveryComment()) - .province(boundaryLabelToNameMap.get(properties.getProvince())) - .district(boundaryLabelToNameMap.get(properties.getDistrict())) - .administrativeProvince(boundaryLabelToNameMap.get(properties.getAdministrativeProvince())) - .locality(boundaryLabelToNameMap.get(properties.getLocality())) - .village(boundaryLabelToNameMap.get(properties.getVillage())) + .province(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getProvince()) : null) + .district(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getDistrict()) : null) + .administrativeProvince(finalBoundaryLabelToNameMap != null ? + finalBoundaryLabelToNameMap.get(properties.getAdministrativeProvince()) : null) + .locality(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getLocality()) : null) + .village(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getVillage()) : null) .latitude(task.getAddress().getLatitude()) .longitude(task.getAddress().getLongitude()) .createdTime(task.getAuditDetails().getCreatedTime()) .createdBy(task.getAuditDetails().getCreatedBy()) .lastModifiedTime(task.getAuditDetails().getLastModifiedTime()) .lastModifiedBy(task.getAuditDetails().getLastModifiedBy()) + .isDeleted(task.getIsDeleted()) .build() ).collect(Collectors.toList()); } diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTransformationService.java index d45c82d7c14..a9e1d11dde7 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTransformationService.java @@ -6,7 +6,7 @@ import org.egov.transformer.config.TransformerProperties; import org.egov.transformer.enums.Operation; import org.egov.transformer.models.downstream.ProjectIndexV1; -import org.egov.transformer.producer.Producer; +import org.egov.common.producer.Producer; import org.egov.transformer.service.transformer.Transformer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -70,7 +70,7 @@ static class ProjectIndexV1Transformer implements @Override public List transform(Project project) { Map boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMap(project, project.getAddress().getBoundary()); + .getBoundaryCodeToNameMap(project.getAddress().getBoundary(), project.getTenantId()); log.info("boundary labels {}", boundaryLabelToNameMap.toString()); List targets = project.getTargets(); if (targets == null || targets.isEmpty()) { diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceDefinitionService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceDefinitionService.java new file mode 100644 index 00000000000..ef694f513f8 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceDefinitionService.java @@ -0,0 +1,84 @@ +package org.egov.transformer.service; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.request.User; +import org.egov.tracer.model.CustomException; +import org.egov.transformer.config.TransformerProperties; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.transformer.models.upstream.ServiceDefinition; +import org.egov.transformer.models.upstream.ServiceDefinitionCriteria; +import org.egov.transformer.models.upstream.ServiceDefinitionResponse; +import org.egov.transformer.models.upstream.ServiceDefinitionSearchRequest; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class ServiceDefinitionService { + + + private final TransformerProperties transformerProperties; + private final ServiceRequestClient serviceRequestClient; + private static final Map serviceMap = new ConcurrentHashMap<>(); + + + public ServiceDefinitionService( TransformerProperties transformerProperties, ServiceRequestClient serviceRequestClient) { + + + this.transformerProperties = transformerProperties; + + this.serviceRequestClient = serviceRequestClient; + } + + public ServiceDefinition getServiceDefinition(String serviceDefId, String tenantId) { + + if (serviceMap.containsKey(serviceDefId)) { + log.info("getting project {} from cache",serviceDefId); + return serviceMap.get(serviceDefId); + } + List serviceDefinitionList = searchServiceDefinition(serviceDefId, tenantId); + ServiceDefinition serviceDefinition=null; + if (!serviceDefinitionList.isEmpty()) { + serviceDefinition = serviceDefinitionList.get(0); + serviceMap.put(serviceDefId, serviceDefinition); + } + return serviceDefinition; + } + + private List searchServiceDefinition(String serviceDefId, String tenantId) { + + ServiceDefinitionSearchRequest request = ServiceDefinitionSearchRequest.builder() + .serviceDefinitionCriteria(ServiceDefinitionCriteria.builder().ids(Collections.singletonList(serviceDefId)).tenantId(tenantId).build()) + .requestInfo(RequestInfo.builder() + .userInfo(User.builder() + .uuid("transformer-uuid") + .build()) + .build()) + .build(); + + + ServiceDefinitionResponse response; + try { + StringBuilder uri = new StringBuilder(); + uri.append(transformerProperties.getServiceDefinitionHost()) + .append(transformerProperties.getServiceDefinitionSearchUrl()) + .append("?limit=").append(transformerProperties.getSearchApiLimit()) + .append("&offset=0") + .append("&ids=").append(serviceDefId) + .append("&tenantId=").append(tenantId); + response = serviceRequestClient.fetchResult(uri, + request, + ServiceDefinitionResponse.class); + } catch (Exception e) { + log.error("error while fetching serviceDefinition list", e); + throw new CustomException("ServiceDefinition_FETCH_ERROR", + "error while fetching service details for id: " + serviceDefId); + } + return response.getServiceDefinition(); + } +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskIndexV1TransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskIndexV1TransformationService.java new file mode 100644 index 00000000000..403756acfe6 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskIndexV1TransformationService.java @@ -0,0 +1,29 @@ +package org.egov.transformer.service; + +import lombok.extern.slf4j.Slf4j; +import org.egov.transformer.config.TransformerProperties; +import org.egov.transformer.models.upstream.Service; +import org.egov.common.producer.Producer; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +@Slf4j +public class ServiceTaskIndexV1TransformationService extends ServiceTaskTransformationService { + + + protected ServiceTaskIndexV1TransformationService(ServiceTaskIndexV1Transformer transformer, Producer producer, TransformerProperties properties) { + super(transformer, producer, properties); + } + + @Override + public void transform(List payloadList) { + super.transform(payloadList); + } + @Override + public String getTopic() { + return properties.getTransformerProducerServiceTaskIndexV1Topic(); + } + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java new file mode 100644 index 00000000000..3d743e98750 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java @@ -0,0 +1,99 @@ +package org.egov.transformer.service; + + +import lombok.extern.slf4j.Slf4j; +import org.egov.transformer.config.TransformerProperties; +import org.egov.transformer.enums.Operation; +import org.egov.transformer.models.downstream.ServiceIndexV1; +import org.egov.transformer.models.upstream.Service; +import org.egov.transformer.models.upstream.ServiceDefinition; +import org.egov.common.producer.Producer; +import org.egov.transformer.service.transformer.Transformer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +@Slf4j +public abstract class ServiceTaskTransformationService implements TransformationService { + + protected final ServiceTaskIndexV1Transformer transformer; + + protected final Producer producer; + + protected final TransformerProperties properties; + + @Autowired + protected ServiceTaskTransformationService(ServiceTaskTransformationService.ServiceTaskIndexV1Transformer transformer, + Producer producer, TransformerProperties properties) { + this.transformer = transformer; + this.producer = producer; + this.properties = properties; + } + + @Override + public void transform(List payloadList) { + log.info("transforming for ids {}", payloadList.stream() + .map(Service::getId).collect(Collectors.toList())); + List transformedPayloadList = payloadList.stream() + .map(transformer::transform) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + log.info("transformation successful"); + producer.push(getTopic(), + transformedPayloadList); + } + + public abstract String getTopic(); + + @Override + public Operation getOperation() { + return Operation.SERVICE; + } + + @Component + static class ServiceTaskIndexV1Transformer implements + Transformer { + private final ProjectService projectService; + private final TransformerProperties properties; + private final ServiceDefinitionService serviceDefinitionService; + + @Autowired + ServiceTaskIndexV1Transformer(ProjectService projectService, TransformerProperties properties, ServiceDefinitionService serviceDefinitionService) { + + this.projectService = projectService; + this.properties = properties; + this.serviceDefinitionService = serviceDefinitionService; + } + + @Override + public List transform(Service service) { + + ServiceDefinition serviceDefinition = serviceDefinitionService.getServiceDefinition(service.getServiceDefId(), service.getTenantId()); + String[] parts = serviceDefinition.getCode().split("\\."); + String projectName = parts[0]; + String supervisorLevel = parts[2]; + String projectId = projectService.getProjectByName(projectName, service.getTenantId()).getId(); + Map boundaryLabelToNameMap = projectService.getBoundaryCodeToNameMapByProjectId(projectId, service.getTenantId()); + log.info("boundary labels {}", boundaryLabelToNameMap.toString()); + + return Collections.singletonList(ServiceIndexV1.builder() + .id(service.getId()) + .projectId(projectId) + .serviceDefinitionId(service.getServiceDefId()) + .supervisorLevel(supervisorLevel) + .checklistName(serviceDefinition.getCode()) + .province(boundaryLabelToNameMap.get(properties.getProvince())) + .district(boundaryLabelToNameMap.get(properties.getDistrict())) + .createdTime(service.getAuditDetails().getCreatedTime()) + .createdBy(service.getAuditDetails().getCreatedBy()) + .tenantId(service.getTenantId()) + .userId(service.getAccountId()) + .attributes(service.getAttributes()) + .build()); + } + } +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/StockIndexV1TransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/StockIndexV1TransformationService.java index 268ce898c8c..e0b4ac41750 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/StockIndexV1TransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/StockIndexV1TransformationService.java @@ -3,7 +3,7 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.stock.Stock; import org.egov.transformer.config.TransformerProperties; -import org.egov.transformer.producer.Producer; +import org.egov.common.producer.Producer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java index 761022be6e7..7bc8e963fc0 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java @@ -2,11 +2,13 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.facility.Facility; +import org.egov.common.models.stock.ReferenceIdType; +import org.egov.common.models.stock.SenderReceiverType; import org.egov.common.models.stock.Stock; import org.egov.transformer.config.TransformerProperties; import org.egov.transformer.enums.Operation; import org.egov.transformer.models.downstream.StockIndexV1; -import org.egov.transformer.producer.Producer; +import org.egov.common.producer.Producer; import org.egov.transformer.service.transformer.Transformer; import org.springframework.stereotype.Component; @@ -74,21 +76,32 @@ static class StockIndexV1Transformer implements @Override public List transform(Stock stock) { Map boundaryLabelToNameMap = null; - if (stock.getReferenceIdType().equals(PROJECT)) { + Facility facility = null; + if (stock.getSenderType().equals(SenderReceiverType.WAREHOUSE)) { + facility = facilityService.findFacilityById(stock.getSenderId(), stock.getTenantId()); + } + if (facility != null && facility.getAddress().getLocality() != null && facility.getAddress().getLocality().getCode() != null) { boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMap(stock.getReferenceId(), stock.getTenantId()); + .getBoundaryCodeToNameMap(facility.getAddress().getLocality().getCode(), stock.getTenantId()); + } else { + if (stock.getReferenceIdType().equals(ReferenceIdType.PROJECT)) { + boundaryLabelToNameMap = projectService + .getBoundaryCodeToNameMapByProjectId(stock.getReferenceId(), stock.getTenantId()); + } } - Facility facility = facilityService.findFacilityById(stock.getFacilityId(), stock.getTenantId());; return Collections.singletonList(StockIndexV1.builder() .id(stock.getId()) .productVariant(stock.getProductVariantId()) - .facilityId(stock.getFacilityId()) + .facilityId(stock.getSenderId()) + .facilityName(facility != null ? facility.getName() : stock.getSenderId()) .physicalCount(stock.getQuantity()) .eventType(stock.getTransactionType()) .reason(stock.getTransactionReason()) - .eventTimeStamp(stock.getAuditDetails().getLastModifiedTime()) + .eventTimeStamp(stock.getDateOfEntry() != null ? + stock.getDateOfEntry() : stock.getAuditDetails().getLastModifiedTime()) .createdTime(stock.getAuditDetails().getCreatedTime()) + .dateOfEntry(stock.getDateOfEntry()) .createdBy(stock.getAuditDetails().getCreatedBy()) .lastModifiedTime(stock.getAuditDetails().getLastModifiedTime()) .lastModifiedBy(stock.getAuditDetails().getLastModifiedBy()) diff --git a/health-services/transformer/src/main/resources/application.properties b/health-services/transformer/src/main/resources/application.properties index bbb0b11d689..cab2e828256 100644 --- a/health-services/transformer/src/main/resources/application.properties +++ b/health-services/transformer/src/main/resources/application.properties @@ -73,9 +73,15 @@ transformer.consumer.bulk.create.stock.topic=save-stock-topic transformer.consumer.bulk.update.stock.topic=update-stock-topic transformer.producer.bulk.stock.index.v1.topic=transformer-producer-bulk-stock-index-v1-topic +transformer.consumer.create.service.topic=save-service +transformer.producer.service.task.index.v1.topic=transformer-producer-service-task-index-v1-topic + egov.project.host=http://localhost:8083 egov.search.project.url=/project/v1/_search +egov.servicedefinition.host=http://localhost:8280 +egov.search.servicedefinition.url=/service-request/service/definition/v1/_search + #egov.location.host=https://health-dev.digit.org egov.location.host=http://localhost:8085 egov.location.endpoint=/egov-location/location/v11/boundarys/_search @@ -88,6 +94,7 @@ project.mdms.module=HCM-PROJECT-TYPES egov.facility.host=http://localhost:8084 egov.search.facility.url=/facility/v1/_search + transformer.consumer.bulk.create.facility.topic=save-facility-topic transformer.consumer.bulk.update.facility.topic=update-facility-topic @@ -95,4 +102,10 @@ boundary.label.name.province="Province" boundary.label.name.district="District" boundary.label.name.administrativeProvince="AdministrativeProvince" boundary.label.name.locality="Locality" -boundary.label.name.village="Village" \ No newline at end of file +boundary.label.name.village="Village" + +# BOUNDARY SERVICE +egov.boundary.host=http://localhost:8081 +egov.boundary.search.url=/boundary-service/boundary/_search +egov.boundary.relationship.search.url=/boundary-service/boundary-relationships/_search +egov.boundary.hierarchy.name=HCM-Moz-Hierarchy diff --git a/health-services/transformer/src/test/java/org/egov/transformer/location/TreeGeneratorTest.java b/health-services/transformer/src/test/java/org/egov/transformer/location/TreeGeneratorTest.java deleted file mode 100644 index 438bc1c70d7..00000000000 --- a/health-services/transformer/src/test/java/org/egov/transformer/location/TreeGeneratorTest.java +++ /dev/null @@ -1,169 +0,0 @@ -package org.egov.transformer.location; - -import lombok.extern.slf4j.Slf4j; -import org.egov.common.models.transformer.upstream.Boundary; -import org.egov.transformer.boundary.BoundaryNode; -import org.egov.transformer.boundary.BoundaryTree; -import org.egov.transformer.boundary.TreeGenerator; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -@Slf4j -class TreeGeneratorTest { - - private TreeGenerator treeGenerator; - - @BeforeEach - void setUp() { - treeGenerator = new TreeGenerator(); - } - - private static List getTestBoundaryList() { - List boundaryList = new ArrayList<>(); - boundaryList.add(Boundary.builder() - .code("LC00001") - .name("Tete") - .label("Province") - .children(Arrays.asList(Boundary.builder() - .code("LC00002") - .name("Angónia") - .label("District") - .children(Arrays.asList(Boundary.builder() - .code("LC00003") - .name("Ulongué") - .label("AdministrativeProvince") - .children(Arrays.asList(Boundary.builder() - .code("LC00004") - .name("TAU L1") - .label("Locality") - .build(), - Boundary.builder() - .code("LC00007") - .name("TAU L2 V1") - .label("Village") - .children(Arrays.asList()) - .build())) - .build(), - Boundary.builder() - .code("LC000010") - .name("Dómuè") - .label("AdministrativeProvince") - .build())) - .build())) - .build()); - return boundaryList; - } - - @Test - void shouldGenerateATreeWithNodeHavingNoChildren() { - List boundaryList = new ArrayList<>(); - boundaryList.add(Boundary.builder() - .code("LC00001") - .name("Tete") - .label("Province") - .build()); - BoundaryTree boundaryTree = treeGenerator.generateTree(boundaryList.get(0)); - assertEquals("LC00001", boundaryTree.getBoundaryNode().getCode()); - assertNull(boundaryTree.getParent()); - assertNull(boundaryTree.getBoundaryTrees()); - } - - @Test - void shouldGenerateATreeWithNodeHavingOneChild() { - List boundaryList = new ArrayList<>(); - boundaryList.add(Boundary.builder() - .code("LC00001") - .name("Tete") - .label("Province") - .children(Arrays.asList(Boundary.builder() - .code("LC00002") - .name("Angónia") - .label("District") - .build())) - .build()); - BoundaryTree boundaryTree = treeGenerator.generateTree(boundaryList.get(0)); - assertTrue(boundaryTree.getBoundaryTrees().stream() - .anyMatch(b -> b.getBoundaryNode().getCode().equals("LC00002"))); - assertEquals("LC00001", boundaryTree.getBoundaryTrees() - .stream().findFirst().get().getParent().getBoundaryNode().getCode()); - } - - @Test - void shouldGenerateATreeWithNodeHavingTwoChildrenOfAChild() { - List boundaryList = new ArrayList<>(); - boundaryList.add(Boundary.builder() - .code("LC00001") - .name("Tete") - .label("Province") - .children(Arrays.asList(Boundary.builder() - .code("LC00002") - .name("Angónia") - .label("District") - .children(Arrays.asList(Boundary.builder() - .code("LC00003") - .name("Ulongué") - .label("AdministrativeProvince") - .build(), - Boundary.builder() - .code("LC000010") - .name("Dómuè") - .label("AdministrativeProvince") - .build())) - .build())) - .build()); - BoundaryTree boundaryTree = treeGenerator.generateTree(boundaryList.get(0)); - assertTrue(boundaryTree.getBoundaryTrees().stream() - .filter(b -> b.getBoundaryNode().getCode().equals("LC00002")).findFirst() - .filter(b -> b.getBoundaryTrees().stream().findAny().isPresent()).isPresent()); - assertEquals("LC00002", boundaryTree.getBoundaryTrees().stream() - .filter(b -> b.getBoundaryNode().getCode().equals("LC00002")) - .flatMap(b -> b.getBoundaryTrees().stream() - .filter(b2 -> b2.getBoundaryNode().getCode().equals("LC000010"))) - .findFirst() - .get().getParent().getBoundaryNode().getCode()); - } - - @Test - void shouldGenerateATreeWithNodeHavingTwoChildrenOfAChildAndTwoChildrenOfOneChildrenOfAChild() { - List boundaryList = getTestBoundaryList(); - BoundaryTree boundaryTree = treeGenerator.generateTree(boundaryList.get(0)); - assertTrue(boundaryTree.getBoundaryTrees().stream() - .filter(b -> b.getBoundaryNode().getCode().equals("LC00002")) - .map(b -> b.getBoundaryTrees().stream() - .filter(b2 -> b2.getBoundaryNode().getCode().equals("LC00003")) - .map(b3 -> b3.getBoundaryTrees().size() == 2)).findAny().isPresent()); - } - - @Test - void shouldReturnTrueIfAGivenBoundaryNodeExistsInTheTree() { - List boundaryList = getTestBoundaryList(); - BoundaryTree boundaryTree = treeGenerator.generateTree(boundaryList.get(0)); - assertNotNull(treeGenerator.search(boundaryTree, "LC00004")); - } - - @Test - void shouldReturnFalseIfAGivenBoundaryNodeDoesNotExistInTheTree() { - List boundaryList = getTestBoundaryList(); - BoundaryTree boundaryTree = treeGenerator.generateTree(boundaryList.get(0)); - assertNull(treeGenerator.search(boundaryTree, "LC00005")); - } - - @Test - void shouldReturnAFlattenedListOfAllTheParentNodesOfABoundaryNode() { - List boundaryList = getTestBoundaryList(); - BoundaryTree root = treeGenerator.generateTree(boundaryList.get(0)); - BoundaryTree found = treeGenerator.search(root, "LC00004"); - List parentNodes = found.getParentNodes(); - assertEquals(3, parentNodes.size()); - log.info(parentNodes.toString()); - } -} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000000..fb57ccd13af --- /dev/null +++ b/yarn.lock @@ -0,0 +1,4 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + +