diff --git a/.github/actions/analyse/action.yml b/.github/actions/analyse/action.yml index 0afba00238..e2666293de 100644 --- a/.github/actions/analyse/action.yml +++ b/.github/actions/analyse/action.yml @@ -23,7 +23,7 @@ runs: shell: bash - name: Publish test reports - uses: mikepenz/action-junit-report@9379f0ccddcab154835d4e2487555ee79614fe95 # v4.2.1 + uses: mikepenz/action-junit-report@ac30be7acb0a361e5492575ab42e47fcadec4928 # v4.2.2 if: always() && github.actor != 'dependabot[bot]' with: check_name: |- diff --git a/.github/actions/format-code/action.yml b/.github/actions/format-code/action.yml index 2b12b44f7e..de4e9f11af 100644 --- a/.github/actions/format-code/action.yml +++ b/.github/actions/format-code/action.yml @@ -60,7 +60,7 @@ runs: env: mask: ${{ inputs.mask }} - - uses: planetscale/ghcommit-action@b662a9d7235a07e80d976152ed5afe41651c4973 # v0.2.9 + - uses: planetscale/ghcommit-action@c8ba2501e51d7257efb393109e6e10bc36a3f769 # v0.1.40 with: commit_message: ${{ inputs.commit_message }} repo: ${{ github.repository }} diff --git a/.github/actions/render-project-template/action.yml b/.github/actions/render-project-template/action.yml index f2638f0eee..7e1a48fa06 100644 --- a/.github/actions/render-project-template/action.yml +++ b/.github/actions/render-project-template/action.yml @@ -30,6 +30,7 @@ runs: sed -i '/add new projects here/a \ "${{ inputs.project_name }}",' settings.gradle.kts sed -i '/add new projects here/i \ - '"'"'["${{ inputs.project_name }}"]'"'"'' .github/workflows/access.yml sed -i '/add new projects here/i \ - '"'"'["${{ inputs.project_name }}"]'"'"'' .github/workflows/deploy.yml + sed -i '/add new projects here/i \ - '"'"'["${{ inputs.project_name }}"]'"'"'' .github/workflows/service-catalogue.yml sed -i '/add new projects here/i \ - ${{ inputs.project_name }}' .github/workflows/build.yml sed -i '/add new projects here/i \* [${{ steps.project_name.outputs.title_case }}](https://ministryofjustice.github.io/hmpps-probation-integration-services/tech-docs/projects/${{ inputs.project_name }})' doc/tech-docs/source/services.html.md.erb sed 's/$SERVICE_NAME/${{ inputs.project_name }}/g' templates/runConfiguration.xml > '.idea/runConfigurations/${{ steps.project_name.outputs.underscore }}.xml' diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 4e624479c6..a9e103eda9 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -32,7 +32,7 @@ jobs: passphrase: ${{ secrets.BOT_GPG_PASSPHRASE }} git_user_signingkey: true git_commit_gpgsign: true - - uses: gradle-update/update-gradle-wrapper-action@v1 + - uses: gradle-update/update-gradle-wrapper-action@0407394b9d173dfc9cf5695f9f560fef6d61a5fe # v1 with: labels: dependencies repo-token: ${{ secrets.BOT_GITHUB_TOKEN }} @@ -41,6 +41,6 @@ jobs: if [ "$(git branch --show-current)" != main ]; then git config --local user.name probation-integration-bot git config --local user.email probation-integration-team@digital.justice.gov.uk - git commit --amend --reset-author --no-edit + git rebase --exec 'git commit --amend --reset-author --no-edit' "HEAD~$(find . -type f -name gradlew | wc -l)" git push --set-upstream origin "$(git branch --show-current)" --force fi diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index a0f29f50c6..9ae8b7b725 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -38,7 +38,7 @@ jobs: echo >> projects/${{ matrix.project }}/.trivyignore - name: Scan image - uses: aquasecurity/trivy-action@b2933f565dbc598b29947660e66259e3c7bc8561 # v0.20.0 + uses: aquasecurity/trivy-action@fd25fed6972e341ff0007ddb61f77e88103953c2 # v0.21.0 with: image-ref: 'ghcr.io/ministryofjustice/hmpps-probation-integration-services/${{ matrix.project }}:latest' ignore-unfixed: true @@ -56,7 +56,7 @@ jobs: sarif_file: 'trivy-results.sarif' - name: Get Trivy results - uses: aquasecurity/trivy-action@b2933f565dbc598b29947660e66259e3c7bc8561 # v0.20.0 + uses: aquasecurity/trivy-action@fd25fed6972e341ff0007ddb61f77e88103953c2 # v0.21.0 with: image-ref: 'ghcr.io/ministryofjustice/hmpps-probation-integration-services/${{ matrix.project }}:latest' ignore-unfixed: true diff --git a/.github/workflows/service-catalogue.yml b/.github/workflows/service-catalogue.yml new file mode 100644 index 0000000000..7d5ebe976e --- /dev/null +++ b/.github/workflows/service-catalogue.yml @@ -0,0 +1,156 @@ +name: Service catalogue +# Add projects to the HMPPS Service Catalogue + +on: + workflow_dispatch: + inputs: + projects: + description: Project + type: choice + required: true + options: + - 'All' + - '["accredited-programmes-and-oasys"]' + - '["approved-premises-and-delius"]' + - '["approved-premises-and-oasys"]' + - '["arns-and-delius"]' + - '["assessment-summary-and-delius"]' + - '["cas2-and-delius"]' + - '["cas3-and-delius"]' + - '["core-person-record-and-delius"]' + - '["court-case-and-delius"]' + - '["create-and-vary-a-licence-and-delius"]' + - '["custody-key-dates-and-delius"]' + - '["domain-events-and-delius"]' + - '["dps-and-delius"]' + - '["effective-proposal-framework-and-delius"]' + - '["external-api-and-delius"]' + - '["hdc-licences-and-delius"]' + - '["hmpps-auth-and-delius"]' + - '["make-recall-decisions-and-delius"]' + - '["manage-offences-and-delius"]' + - '["manage-pom-cases-and-delius"]' + - '["manage-supervision-and-delius"]' + - '["manage-supervision-and-oasys"]' + - '["oasys-and-delius"]' + - '["offender-events-and-delius"]' + - '["opd-and-delius"]' + - '["pathfinder-and-delius"]' + - '["person-search-index-from-delius"]' + - '["pre-sentence-reports-to-delius"]' + - '["prison-case-notes-to-probation"]' + - '["prison-custody-status-to-delius"]' + - '["prison-education-and-delius"]' + - '["prison-identifier-and-delius"]' + - '["prisoner-profile-and-delius"]' + - '["probation-search-and-delius"]' + - '["refer-and-monitor-and-delius"]' + - '["resettlement-passport-and-delius"]' + - '["risk-assessment-scores-to-delius"]' + - '["sentence-plan-and-delius"]' + - '["sentence-plan-and-oasys"]' + - '["soc-and-delius"]' + - '["tier-to-delius"]' + - '["unpaid-work-and-delius"]' + - '["workforce-allocations-to-delius"]' + # ^ add new projects here + # GitHub Actions doesn't support dynamic choices, we must add each project here to enable manual deployments + # See https://github.com/community/community/discussions/11795 + push: + branches: + - main + paths: + - 'projects/**/deploy' + +jobs: + get-projects: + outputs: + projects: ${{ steps.output.outputs.projects }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - id: check-changes + if: github.event_name == 'push' + uses: ./.github/actions/check-changes + with: + filters: | + projects: + - 'projects/**/deploy' + - name: Get projects - changed + if: github.event_name == 'push' + run: echo "projects=$PROJECTS" | tee -a "$GITHUB_ENV" + env: + PROJECTS: ${{ steps.check-changes.outputs.projects }} + - name: Get projects - all + if: github.event_name == 'workflow_dispatch' && inputs.projects == 'All' + run: echo "projects=$(find projects -mindepth 1 -maxdepth 1 -printf "%f\n" | jq --raw-input . | jq --slurp --compact-output .)" | tee -a "$GITHUB_ENV" + - name: Get projects - selected + if: github.event_name == 'workflow_dispatch' && inputs.projects != 'All' + run: echo 'projects=${{ inputs.projects }}' | tee -a "$GITHUB_ENV" + - id: output + run: echo 'projects=${{ env.projects }}' | tee -a "$GITHUB_OUTPUT" + + update-catalogue: + runs-on: ubuntu-latest + needs: get-projects + strategy: + fail-fast: false + matrix: + project: ${{ fromJson(needs.get-projects.outputs.projects) }} + steps: + - uses: actions/checkout@v4 + + - uses: ./.github/actions/cloud-platform-auth + with: + api: ${{ secrets.KUBE_ENV_API }} + cert: ${{ secrets.KUBE_CERT }} + cluster: ${{ secrets.KUBE_CLUSTER }} + namespace: ${{ secrets.KUBE_NAMESPACE }} + token: ${{ secrets.KUBE_TOKEN }} + + - name: Get environment details + id: environments + run: | + environments=[] + for env in dev preprod prod; do + values_file="projects/$PROJECT_NAME/deploy/values-$env.yml" + if [ -f "$values_file" ] && [ "$(yq '.enabled' "$values_file" | sed 's/^null$/true/')" = "true" ] && [ -n "$(yq '.generic-service.ingress.host' "$values_file")" ]; then + url=$(yq '.generic-service.ingress.host' "$values_file") + health_path=$(yq '.generic-service.livenessProbe.httpGet.path // "/health"' "projects/$PROJECT_NAME/deploy/values.yaml") + environments=$(echo "$environments" | jq -c '. += [{ + "name": $name, + "type": $name, + "url": ("https://" + $url), + "health_path": $health_path, + "info_path": "/info", + "namespace": ("hmpps-probation-integration-services-" + $name) + }]' --arg name "$env" --arg url "$url" --arg health_path "$health_path") + fi + done + echo "environments=$environments" | tee -a "$GITHUB_OUTPUT" + env: + PROJECT_NAME: ${{ matrix.project }} + + - name: Update catalogue + run: | + ./script/start-service-pod.sh + PROJECT_TITLE="$(awk 'BEGIN {RS=""; FS="\n"} !/^[#\/]/ {gsub("\n", " ", $0); sub(/\. .*/, "."); print; exit}' "projects/$PROJECT_NAME/README.md")" # First line of the project's README.md + kubectl cp ./script/update-service-catalogue.sh "$POD_NAME:/tmp/update-service-catalogue.sh" + kubectl exec "$POD_NAME" -- env \ + PROJECT_NAME="$PROJECT_NAME" \ + PROJECT_TITLE="$PROJECT_TITLE" \ + ENVIRONMENTS="$ENVIRONMENTS" \ + SERVICE_CATALOGUE_API_KEY="$SERVICE_CATALOGUE_API_KEY" \ + /tmp/update-service-catalogue.sh + env: + NAMESPACE: ${{ secrets.KUBE_NAMESPACE }} + POD_NAME: sc-${{ matrix.project }} + PROJECT_NAME: ${{ matrix.project }} + ENVIRONMENTS: ${{ steps.environments.outputs.environments }} + SERVICE_CATALOGUE_API_KEY: ${{ secrets.SERVICE_CATALOGUE_API_KEY }} + + - name: Delete pod + if: always() + run: kubectl delete pod "$POD_NAME" || true + env: + POD_NAME: sc-${{ matrix.project }} diff --git a/.gitignore b/.gitignore index 0c452acd11..ae7295032b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ build/ !**/src/main/**/build/ !**/src/test/**/build/ +### Kotlin 2.0 ### +.kotlin + ### STS ### .apt_generated .classpath diff --git a/build.gradle.kts b/build.gradle.kts index 8bf08ae7e7..e344942ec3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,5 @@ import com.gorylenko.GenerateGitPropertiesTask -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.noarg.gradle.NoArgExtension import org.springframework.boot.gradle.tasks.buildinfo.BuildInfo import org.springframework.boot.gradle.tasks.bundling.BootJar @@ -8,10 +8,9 @@ import uk.gov.justice.digital.hmpps.plugins.ClassPathPlugin import uk.gov.justice.digital.hmpps.plugins.JibConfigPlugin plugins { - kotlin("jvm") version "1.9.24" - kotlin("plugin.spring") version "1.9.24" apply false - kotlin("plugin.jpa") version "1.9.24" apply false - kotlin("kapt") version "1.9.24" apply false + kotlin("jvm") version "2.0.0" + kotlin("plugin.spring") version "2.0.0" apply false + kotlin("plugin.jpa") version "2.0.0" apply false id("org.springframework.boot") version "3.2.5" apply false id("io.spring.dependency-management") version "1.1.5" apply false id("com.gorylenko.gradle-git-properties") version "2.4.2" apply false @@ -40,18 +39,22 @@ allprojects { mavenCentral() } + apply { + plugin("org.jetbrains.kotlin.jvm") + } + + kotlin { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_21) + freeCompilerArgs.add("-Xjsr305=strict") // to make use of Spring's null-safety annotations + } + } + tasks { withType { sourceCompatibility = "21" } - withType { - kotlinOptions { - freeCompilerArgs = listOf("-Xjsr305=strict") - jvmTarget = "21" - } - } - withType { enabled = false } @@ -59,19 +62,20 @@ allprojects { } subprojects { - apply { plugin("org.springframework.boot") } - apply { plugin("io.spring.dependency-management") } - apply { plugin("org.jetbrains.kotlin.jvm") } - apply { plugin("org.jetbrains.kotlin.kapt") } - apply { plugin("org.jetbrains.kotlin.plugin.jpa") } - apply { plugin("org.jetbrains.kotlin.plugin.spring") } - apply { plugin("jacoco") } - apply { plugin("test-report-aggregation") } - apply { plugin("jacoco-report-aggregation") } - apply { plugin("org.sonarqube") } - apply { plugin("com.gorylenko.gradle-git-properties") } - apply { plugin(JibConfigPlugin::class.java) } - apply { plugin(ClassPathPlugin::class.java) } + apply { + plugin("org.springframework.boot") + plugin("io.spring.dependency-management") + plugin("org.jetbrains.kotlin.jvm") + plugin("org.jetbrains.kotlin.plugin.jpa") + plugin("org.jetbrains.kotlin.plugin.spring") + plugin("jacoco") + plugin("test-report-aggregation") + plugin("jacoco-report-aggregation") + plugin("org.sonarqube") + plugin("com.gorylenko.gradle-git-properties") + plugin(JibConfigPlugin::class.java) + plugin(ClassPathPlugin::class.java) + } tasks { withType { diff --git a/doc/tech-docs/source/concepts.html.md.erb b/doc/tech-docs/source/concepts.html.md.erb index 9b718bebe7..879b3036a9 100644 --- a/doc/tech-docs/source/concepts.html.md.erb +++ b/doc/tech-docs/source/concepts.html.md.erb @@ -128,6 +128,27 @@ A practitioner can be a member of one or more teams. Each team is linked to a single [Local Admin Unit](#local-admin-unit-lau), and may also have a linked office location. +### Limited Access + +Alongside role-based access control, access to specific cases in Delius can be controlled via _restrictions_ and +_exclusions_. + +#### Restriction + +Probation cases can be "restricted" to a specific subset of probation practitioners, so that only those practitioners +can access the case details. + +Restrictions act as an _allow list_, and are commonly used for high-profile or sensitive cases that should not be +accessible by everyone. + +#### Exclusion + +Probation cases can also be "excluded" from a subset of probation practitioners, so that those practitioners +specifically cannot access the case details. + +Exclusions act as a _deny list_, and are commonly used for cases where a practitioner may have a personal relationship +with the person on probation. + ## OASys Concepts Probation concepts as modelled in the OASys application diff --git a/projects/accredited-programmes-and-oasys/deploy/values.yaml b/projects/accredited-programmes-and-oasys/deploy/values.yaml index 401e197efa..c378989f87 100644 --- a/projects/accredited-programmes-and-oasys/deploy/values.yaml +++ b/projects/accredited-programmes-and-oasys/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: accredited-programmes-and-oasys image: diff --git a/projects/accredited-programmes-and-oasys/src/main/resources/application.yml b/projects/accredited-programmes-and-oasys/src/main/resources/application.yml index 681c7e408d..467d47eb13 100644 --- a/projects/accredited-programmes-and-oasys/src/main/resources/application.yml +++ b/projects/accredited-programmes-and-oasys/src/main/resources/application.yml @@ -23,6 +23,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/accredited-programmes-and-oasys/tech-docs/Gemfile.lock b/projects/accredited-programmes-and-oasys/tech-docs/Gemfile.lock index 043512b75c..0982b087bc 100644 --- a/projects/accredited-programmes-and-oasys/tech-docs/Gemfile.lock +++ b/projects/accredited-programmes-and-oasys/tech-docs/Gemfile.lock @@ -145,7 +145,8 @@ GEM rb-inotify (0.10.1) ffi (~> 1.0) redcarpet (3.5.1) - rexml (3.2.5) + rexml (3.2.8) + strscan (>= 3.0.9) rouge (3.30.0) sass (3.4.25) sassc (2.4.0) @@ -154,6 +155,7 @@ GEM sprockets (4.2.0) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) + strscan (3.1.0) temple (0.10.0) thor (1.2.1) tilt (2.0.11) diff --git a/projects/approved-premises-and-delius/deploy/values.yaml b/projects/approved-premises-and-delius/deploy/values.yaml index 200f0d8270..948949bd6e 100644 --- a/projects/approved-premises-and-delius/deploy/values.yaml +++ b/projects/approved-premises-and-delius/deploy/values.yaml @@ -1,4 +1,5 @@ generic-service: + productId: HMPPS518 nameOverride: approved-premises-and-delius serviceAccountName: approved-premises-and-delius diff --git a/projects/approved-premises-and-delius/src/main/resources/application.yml b/projects/approved-premises-and-delius/src/main/resources/application.yml index 92a49389ec..eb09c7a76e 100644 --- a/projects/approved-premises-and-delius/src/main/resources/application.yml +++ b/projects/approved-premises-and-delius/src/main/resources/application.yml @@ -40,6 +40,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/approved-premises-and-oasys/deploy/values.yaml b/projects/approved-premises-and-oasys/deploy/values.yaml index 6474067bab..57bb051c5c 100644 --- a/projects/approved-premises-and-oasys/deploy/values.yaml +++ b/projects/approved-premises-and-oasys/deploy/values.yaml @@ -2,6 +2,7 @@ # Values here are the same across all environments # An additional set of default values can be found in templates/helm-defaults.yml, which is the same across all projects generic-service: + productId: HMPPS518 nameOverride: approved-premises-and-oasys image: diff --git a/projects/approved-premises-and-oasys/src/main/resources/application.yml b/projects/approved-premises-and-oasys/src/main/resources/application.yml index 9fc3735aa8..434c4d3c20 100644 --- a/projects/approved-premises-and-oasys/src/main/resources/application.yml +++ b/projects/approved-premises-and-oasys/src/main/resources/application.yml @@ -25,6 +25,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/projects/arns-and-delius/deploy/values.yaml b/projects/arns-and-delius/deploy/values.yaml index 4869c2b0ec..58b08661a5 100644 --- a/projects/arns-and-delius/deploy/values.yaml +++ b/projects/arns-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: arns-and-delius image: diff --git a/projects/arns-and-delius/src/main/resources/application.yml b/projects/arns-and-delius/src/main/resources/application.yml index 52bb7f9527..5c569d98fc 100644 --- a/projects/arns-and-delius/src/main/resources/application.yml +++ b/projects/arns-and-delius/src/main/resources/application.yml @@ -27,6 +27,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/arns-and-delius/tech-docs/Gemfile.lock b/projects/arns-and-delius/tech-docs/Gemfile.lock index 043512b75c..0982b087bc 100644 --- a/projects/arns-and-delius/tech-docs/Gemfile.lock +++ b/projects/arns-and-delius/tech-docs/Gemfile.lock @@ -145,7 +145,8 @@ GEM rb-inotify (0.10.1) ffi (~> 1.0) redcarpet (3.5.1) - rexml (3.2.5) + rexml (3.2.8) + strscan (>= 3.0.9) rouge (3.30.0) sass (3.4.25) sassc (2.4.0) @@ -154,6 +155,7 @@ GEM sprockets (4.2.0) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) + strscan (3.1.0) temple (0.10.0) thor (1.2.1) tilt (2.0.11) diff --git a/projects/assessment-summary-and-delius/deploy/values.yaml b/projects/assessment-summary-and-delius/deploy/values.yaml index 8a65c02996..75de6dcd4e 100644 --- a/projects/assessment-summary-and-delius/deploy/values.yaml +++ b/projects/assessment-summary-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: assessment-summary-and-delius serviceAccountName: assessment-summary-and-delius diff --git a/projects/assessment-summary-and-delius/src/main/resources/application.yml b/projects/assessment-summary-and-delius/src/main/resources/application.yml index 472e07fc8b..d4e9a90501 100644 --- a/projects/assessment-summary-and-delius/src/main/resources/application.yml +++ b/projects/assessment-summary-and-delius/src/main/resources/application.yml @@ -37,6 +37,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/projects/cas2-and-delius/deploy/values.yaml b/projects/cas2-and-delius/deploy/values.yaml index 5c20f4fff9..9b0187fcbe 100644 --- a/projects/cas2-and-delius/deploy/values.yaml +++ b/projects/cas2-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: cas2-and-delius serviceAccountName: cas2-and-delius diff --git a/projects/cas2-and-delius/src/main/resources/application.yml b/projects/cas2-and-delius/src/main/resources/application.yml index 20e44489a1..bbce67c045 100644 --- a/projects/cas2-and-delius/src/main/resources/application.yml +++ b/projects/cas2-and-delius/src/main/resources/application.yml @@ -36,6 +36,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/projects/cas3-and-delius/deploy/values.yaml b/projects/cas3-and-delius/deploy/values.yaml index 4db7bf639a..6d00b2e13c 100644 --- a/projects/cas3-and-delius/deploy/values.yaml +++ b/projects/cas3-and-delius/deploy/values.yaml @@ -1,4 +1,5 @@ generic-service: + productId: HMPPS518 nameOverride: cas3-and-delius serviceAccountName: cas3-and-delius diff --git a/projects/cas3-and-delius/src/main/resources/application.yml b/projects/cas3-and-delius/src/main/resources/application.yml index 6915a57e4d..97c5d77a11 100644 --- a/projects/cas3-and-delius/src/main/resources/application.yml +++ b/projects/cas3-and-delius/src/main/resources/application.yml @@ -38,6 +38,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/projects/cas3-and-delius/tech-docs/Gemfile.lock b/projects/cas3-and-delius/tech-docs/Gemfile.lock index c4f0ebe665..caff8a3c73 100644 --- a/projects/cas3-and-delius/tech-docs/Gemfile.lock +++ b/projects/cas3-and-delius/tech-docs/Gemfile.lock @@ -145,7 +145,8 @@ GEM rb-inotify (0.10.1) ffi (~> 1.0) redcarpet (3.5.1) - rexml (3.2.5) + rexml (3.2.8) + strscan (>= 3.0.9) rouge (3.30.0) sass (3.4.25) sassc (2.4.0) @@ -154,6 +155,7 @@ GEM sprockets (4.2.0) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) + strscan (3.1.0) temple (0.10.0) thor (1.2.1) tilt (2.0.11) diff --git a/projects/core-person-record-and-delius/deploy/values.yaml b/projects/core-person-record-and-delius/deploy/values.yaml index 66f21be524..4a0695b2b9 100644 --- a/projects/core-person-record-and-delius/deploy/values.yaml +++ b/projects/core-person-record-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: core-person-record-and-delius image: diff --git a/projects/core-person-record-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt b/projects/core-person-record-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt index 74d75deaed..c4c837099a 100644 --- a/projects/core-person-record-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt +++ b/projects/core-person-record-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt @@ -34,7 +34,11 @@ class DataLoader( PersonGenerator.MIN_PERSON, PersonGenerator.FULL_PERSON, *PersonGenerator.FULL_PERSON_ALIASES.toTypedArray(), - *PersonGenerator.FULL_PERSON_ADDRESSES.toTypedArray() + *PersonGenerator.FULL_PERSON_ADDRESSES.toTypedArray(), + *PersonGenerator.FULL_PERSON_EXCLUSIONS.map { it.user }.toTypedArray(), + *PersonGenerator.FULL_PERSON_EXCLUSIONS.toTypedArray(), + *PersonGenerator.FULL_PERSON_RESTRICTIONS.map { it.user }.toTypedArray(), + *PersonGenerator.FULL_PERSON_RESTRICTIONS.toTypedArray(), ) } diff --git a/projects/core-person-record-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt b/projects/core-person-record-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt index 0ec748753c..1cb579ade2 100644 --- a/projects/core-person-record-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt +++ b/projects/core-person-record-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt @@ -1,10 +1,8 @@ package uk.gov.justice.digital.hmpps.data.generator -import uk.gov.justice.digital.hmpps.integration.delius.entity.Alias -import uk.gov.justice.digital.hmpps.integration.delius.entity.Person -import uk.gov.justice.digital.hmpps.integration.delius.entity.PersonAddress -import uk.gov.justice.digital.hmpps.integration.delius.entity.ReferenceData +import uk.gov.justice.digital.hmpps.integration.delius.entity.* import java.time.LocalDate +import java.time.LocalDateTime object PersonGenerator { val ETHNICITY = generateReferenceData("ETH") @@ -16,27 +14,29 @@ object PersonGenerator { val MIN_PERSON = generatePerson("M123456", firstname = "Isabelle", surname = "Necessary", dob = LocalDate.of(1990, 3, 5)) val FULL_PERSON = generatePerson( - "F123456", - "A3349EX", - "2011/0593710D", - "89861/11W", - "FJ123456W", - "94600E", - "Frederick", - "Paul", - "Bernard", - "Johnson", - LocalDate.of(1975, 7, 15), - "No Previous", - "Freddy", - "0191 755 4789", - "07895746789", - "fred@gmail.com", - TITLE, - GENDER, - NATIONALITY, - ETHNICITY, - "Description of ethnicity" + crn = "F123456", + nomsId = "A3349EX", + pnc = "2011/0593710D", + cro = "89861/11W", + niNumber = "FJ123456W", + prisonerNumber = "94600E", + firstname = "Frederick", + secondName = "Paul", + thirdName = "Bernard", + surname = "Johnson", + dob = LocalDate.of(1975, 7, 15), + previousSurname = "No Previous", + preferredName = "Freddy", + telephoneNumber = "0191 755 4789", + mobileNumber = "07895746789", + emailAddress = "fred@gmail.com", + title = TITLE, + gender = GENDER, + nationality = NATIONALITY, + ethnicity = ETHNICITY, + ethnicityDescription = "Description of ethnicity", + exclusionMessage = "This case is excluded because ...", + restrictionMessage = "This case is restricted because ..." ) val FULL_PERSON_ALIASES = listOf( @@ -49,6 +49,16 @@ object PersonGenerator { generateAddress(FULL_PERSON.id, MAIN_ADDRESS, "PC1 1TS", LocalDate.now().minusDays(30)) ) + val FULL_PERSON_EXCLUSIONS = listOf( + generateExclusion(FULL_PERSON.id, "SomeUser1"), + generateExclusion(FULL_PERSON.id, "PastEndDatedUser", LocalDateTime.now().minusDays(30)), + ) + + val FULL_PERSON_RESTRICTIONS = listOf( + generateRestriction(FULL_PERSON.id, "SomeUser2"), + generateRestriction(FULL_PERSON.id, "FutureEndDatedUser", LocalDateTime.now().plusDays(30)), + ) + fun generateReferenceData( code: String, description: String = "Description of $code", @@ -77,32 +87,36 @@ object PersonGenerator { nationality: ReferenceData? = null, ethnicity: ReferenceData? = null, ethnicityDescription: String? = null, + exclusionMessage: String? = null, + restrictionMessage: String? = null, softDeleted: Boolean = false, id: Long = IdGenerator.getAndIncrement() ) = Person( - crn, - nomsId, - pnc, - cro, - niNumber, - prisonerNumber, - firstname, - secondName, - thirdName, - surname, - dob, - previousSurname, - preferredName, - telephoneNumber, - mobileNumber, - emailAddress, - title, - gender, - nationality, - ethnicity, - ethnicityDescription, - softDeleted, - id + crn = crn, + nomsId = nomsId, + pnc = pnc, + cro = cro, + niNumber = niNumber, + prisonerNumber = prisonerNumber, + firstName = firstname, + secondName = secondName, + thirdName = thirdName, + surname = surname, + dob = dob, + previousSurname = previousSurname, + preferredName = preferredName, + telephoneNumber = telephoneNumber, + mobileNumber = mobileNumber, + emailAddress = emailAddress, + title = title, + gender = gender, + nationality = nationality, + ethnicity = ethnicity, + ethnicityDescription = ethnicityDescription, + exclusionMessage = exclusionMessage, + restrictionMessage = restrictionMessage, + softDeleted = softDeleted, + id = id, ) fun generateAlias( @@ -125,4 +139,18 @@ object PersonGenerator { softDeleted: Boolean = false, id: Long = IdGenerator.getAndIncrement() ) = PersonAddress(personId, status, postcode, startDate, endDate, softDeleted, id) + + private fun generateExclusion( + personId: Long, + username: String, + endDate: LocalDateTime? = null, + id: Long = IdGenerator.getAndIncrement() + ) = Exclusion(personId, LimitedAccessUser(username, IdGenerator.getAndIncrement()), endDate, id) + + private fun generateRestriction( + personId: Long, + username: String, + endDate: LocalDateTime? = null, + id: Long = IdGenerator.getAndIncrement() + ) = Restriction(personId, LimitedAccessUser(username, IdGenerator.getAndIncrement()), endDate, id) } \ No newline at end of file diff --git a/projects/core-person-record-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/CorePersonIntegrationTest.kt b/projects/core-person-record-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/CorePersonIntegrationTest.kt index dbec730b9f..11bd9d8c79 100644 --- a/projects/core-person-record-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/CorePersonIntegrationTest.kt +++ b/projects/core-person-record-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/CorePersonIntegrationTest.kt @@ -11,6 +11,8 @@ import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import uk.gov.justice.digital.hmpps.api.model.LimitedAccess +import uk.gov.justice.digital.hmpps.api.model.LimitedAccessUser import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator import uk.gov.justice.digital.hmpps.integration.delius.entity.Alias import uk.gov.justice.digital.hmpps.integration.delius.entity.PersonAddress @@ -32,8 +34,16 @@ internal class CorePersonIntegrationTest { val minPerson = PersonGenerator.MIN_PERSON.detail(listOf(), listOf()) val fullPerson = PersonGenerator.FULL_PERSON.detail( - PersonGenerator.FULL_PERSON_ALIASES.map(Alias::asModel), - PersonGenerator.FULL_PERSON_ADDRESSES.mapNotNull(PersonAddress::asAddress) + aliases = PersonGenerator.FULL_PERSON_ALIASES.map(Alias::asModel), + addresses = PersonGenerator.FULL_PERSON_ADDRESSES.mapNotNull(PersonAddress::asAddress), + exclusions = LimitedAccess( + message = "This case is excluded because ...", + users = listOf(LimitedAccessUser("SomeUser1")) + ), + restrictions = LimitedAccess( + message = "This case is restricted because ...", + users = listOf(LimitedAccessUser("SomeUser2"), LimitedAccessUser("FutureEndDatedUser")) + ), ) @Test diff --git a/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/LimitedAccess.kt b/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/LimitedAccess.kt new file mode 100644 index 0000000000..00179951e7 --- /dev/null +++ b/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/LimitedAccess.kt @@ -0,0 +1,10 @@ +package uk.gov.justice.digital.hmpps.api.model + +data class LimitedAccess( + val message: String?, + val users: List +) + +data class LimitedAccessUser( + val username: String +) \ No newline at end of file diff --git a/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/PersonDetail.kt b/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/PersonDetail.kt index badfaf9dfa..d6e9d329a2 100644 --- a/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/PersonDetail.kt +++ b/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/PersonDetail.kt @@ -13,7 +13,9 @@ data class PersonDetail( val ethnicityDescription: String?, val contactDetails: ContactDetails?, val aliases: List, - val addresses: List
+ val addresses: List
, + val excludedFrom: LimitedAccess?, + val restrictedTo: LimitedAccess?, ) data class Identifiers( diff --git a/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integration/delius/entity/LimitedAccess.kt b/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integration/delius/entity/LimitedAccess.kt new file mode 100644 index 0000000000..426a9c2f5f --- /dev/null +++ b/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integration/delius/entity/LimitedAccess.kt @@ -0,0 +1,65 @@ +package uk.gov.justice.digital.hmpps.integration.delius.entity + +import jakarta.persistence.* +import org.hibernate.annotations.Immutable +import org.hibernate.annotations.SQLRestriction +import org.springframework.data.jpa.repository.JpaRepository +import java.time.LocalDateTime + +@Entity +@Immutable +@SQLRestriction("exclusion_end_time is null or exclusion_end_time > current_date") +class Exclusion( + @Column(name = "offender_id") + val personId: Long, + + @ManyToOne + @JoinColumn(name = "user_id") + val user: LimitedAccessUser, + + @Column(name = "exclusion_end_time") + val endDate: LocalDateTime?, + + @Id + @Column(name = "exclusion_id") + val id: Long +) + +@Entity +@Immutable +@SQLRestriction("restriction_end_time is null or restriction_end_time > current_date") +class Restriction( + @Column(name = "offender_id") + val personId: Long, + + @ManyToOne + @JoinColumn(name = "user_id") + val user: LimitedAccessUser, + + @Column(name = "restriction_end_time") + val endDate: LocalDateTime?, + + @Id + @Column(name = "restriction_id") + val id: Long +) + +@Entity +@Immutable +@Table(name = "user_") +class LimitedAccessUser( + @Column(name = "distinguished_name") + val username: String, + + @Id + @Column(name = "user_id") + val id: Long +) + +interface ExclusionRepository : JpaRepository { + fun findByPersonId(personId: Long): List +} + +interface RestrictionRepository : JpaRepository { + fun findByPersonId(personId: Long): List +} diff --git a/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integration/delius/entity/Person.kt b/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integration/delius/entity/Person.kt index eaf68d61b7..ca82aae94b 100644 --- a/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integration/delius/entity/Person.kt +++ b/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integration/delius/entity/Person.kt @@ -74,6 +74,8 @@ data class Person( val ethnicity: ReferenceData?, val ethnicityDescription: String?, + val exclusionMessage: String?, + val restrictionMessage: String?, @Column(name = "soft_deleted", columnDefinition = "number") val softDeleted: Boolean, diff --git a/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonMapping.kt b/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonMapping.kt index 9c33bcb9c5..06f9f252d6 100644 --- a/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonMapping.kt +++ b/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonMapping.kt @@ -1,22 +1,29 @@ package uk.gov.justice.digital.hmpps.service import uk.gov.justice.digital.hmpps.api.model.* -import uk.gov.justice.digital.hmpps.integration.delius.entity.Person -import uk.gov.justice.digital.hmpps.integration.delius.entity.PersonAddress -import uk.gov.justice.digital.hmpps.integration.delius.entity.ReferenceData - -fun Person.detail(aliases: List, addresses: List
) = PersonDetail( - identifiers(), - name(), - dob, - title?.asCodeDescription(), - gender?.asCodeDescription(), - nationality?.asCodeDescription(), - ethnicity?.asCodeDescription(), - ethnicityDescription, - contactDetails(), - aliases, - addresses +import uk.gov.justice.digital.hmpps.api.model.Alias +import uk.gov.justice.digital.hmpps.api.model.LimitedAccessUser +import uk.gov.justice.digital.hmpps.integration.delius.entity.* + +fun Person.detail( + aliases: List, + addresses: List
, + exclusions: LimitedAccess? = null, + restrictions: LimitedAccess? = null, +) = PersonDetail( + identifiers = identifiers(), + name = name(), + dateOfBirth = dob, + title = title?.asCodeDescription(), + gender = gender?.asCodeDescription(), + nationality = nationality?.asCodeDescription(), + ethnicity = ethnicity?.asCodeDescription(), + ethnicityDescription = ethnicityDescription, + contactDetails = contactDetails(), + aliases = aliases, + addresses = addresses, + excludedFrom = exclusions, + restrictedTo = restrictions, ) fun Person.identifiers() = @@ -46,3 +53,16 @@ fun uk.gov.justice.digital.hmpps.integration.delius.entity.Alias.asModel() = Ali fun PersonAddress.asAddress() = postcode?.let { Address(it) } +fun List.exclusionsAsLimitedAccess(message: String?) = if (isNotEmpty()) { + LimitedAccess( + message = message, + users = map { LimitedAccessUser(it.user.username) } + ) +} else null + +fun List.restrictionsAsLimitedAccess(message: String?) = if (isNotEmpty()) { + LimitedAccess( + message = message, + users = map { LimitedAccessUser(it.user.username) } + ) +} else null diff --git a/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt b/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt index 50e5e5416d..89ca9dd50f 100644 --- a/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt +++ b/projects/core-person-record-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/PersonService.kt @@ -10,7 +10,9 @@ import uk.gov.justice.digital.hmpps.integration.delius.entity.* class PersonService( private val personRepository: PersonRepository, private val aliasRepository: AliasRepository, - private val addressRepository: AddressRepository + private val addressRepository: AddressRepository, + private val exclusionRepository: ExclusionRepository, + private val restrictionRepository: RestrictionRepository, ) { fun getPersonDetail(crn: String): PersonDetail = personRepository.getByCrn(crn).withDetail() @@ -19,9 +21,10 @@ class PersonService( fun getAllPersonDetails(pageable: Pageable): Page = personRepository.findAll(pageable).map { it.withDetail() } - private fun Person.withDetail(): PersonDetail = - detail( - aliasRepository.findByPersonId(id).map(Alias::asModel), - addressRepository.mainAddresses(id).mapNotNull(PersonAddress::asAddress) - ) + private fun Person.withDetail() = this.detail( + aliases = aliasRepository.findByPersonId(id).map(Alias::asModel), + addresses = addressRepository.mainAddresses(id).mapNotNull(PersonAddress::asAddress), + exclusions = exclusionRepository.findByPersonId(id).exclusionsAsLimitedAccess(exclusionMessage), + restrictions = restrictionRepository.findByPersonId(id).restrictionsAsLimitedAccess(restrictionMessage), + ) } \ No newline at end of file diff --git a/projects/core-person-record-and-delius/src/main/resources/application.yml b/projects/core-person-record-and-delius/src/main/resources/application.yml index 914c1b79e9..4126e4c9b8 100644 --- a/projects/core-person-record-and-delius/src/main/resources/application.yml +++ b/projects/core-person-record-and-delius/src/main/resources/application.yml @@ -28,6 +28,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/core-person-record-and-delius/tech-docs/Gemfile.lock b/projects/core-person-record-and-delius/tech-docs/Gemfile.lock index 043512b75c..0982b087bc 100644 --- a/projects/core-person-record-and-delius/tech-docs/Gemfile.lock +++ b/projects/core-person-record-and-delius/tech-docs/Gemfile.lock @@ -145,7 +145,8 @@ GEM rb-inotify (0.10.1) ffi (~> 1.0) redcarpet (3.5.1) - rexml (3.2.5) + rexml (3.2.8) + strscan (>= 3.0.9) rouge (3.30.0) sass (3.4.25) sassc (2.4.0) @@ -154,6 +155,7 @@ GEM sprockets (4.2.0) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) + strscan (3.1.0) temple (0.10.0) thor (1.2.1) tilt (2.0.11) diff --git a/projects/court-case-and-delius/deploy/values.yaml b/projects/court-case-and-delius/deploy/values.yaml index 20d9913199..16e94b224d 100644 --- a/projects/court-case-and-delius/deploy/values.yaml +++ b/projects/court-case-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: court-case-and-delius image: diff --git a/projects/court-case-and-delius/src/main/resources/application.yml b/projects/court-case-and-delius/src/main/resources/application.yml index f883963b86..6d586aaedd 100644 --- a/projects/court-case-and-delius/src/main/resources/application.yml +++ b/projects/court-case-and-delius/src/main/resources/application.yml @@ -38,6 +38,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/create-and-vary-a-licence-and-delius/deploy/values.yaml b/projects/create-and-vary-a-licence-and-delius/deploy/values.yaml index 7b8a7e2de0..244d78f687 100644 --- a/projects/create-and-vary-a-licence-and-delius/deploy/values.yaml +++ b/projects/create-and-vary-a-licence-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: create-and-vary-a-licence-and-delius serviceAccountName: create-and-vary-a-licence-and-delius diff --git a/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt b/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt index 8609bd32a3..f26472dbbe 100644 --- a/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt +++ b/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt @@ -57,15 +57,6 @@ class DataLoader( val person = PersonGenerator.generatePerson("N123456").also(entityManager::persist) PersonGenerator.generateManager(person).also(entityManager::persist) - entityManager.persistAll( - AddressGenerator.ADDRESS_STATUS_MAIN, - AddressGenerator.ADDRESS_STATUS_PREVIOUS, - AddressGenerator.ADDRESS_STATUS_OTHER, - AddressGenerator.ADDRESS_MAIN, - AddressGenerator.ADDRESS_PREVIOUS, - AddressGenerator.ADDRESS_OTHER, - AddressGenerator.ADDRESS_DELETED - ) createForAddingLicenceConditions() diff --git a/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/AddressGenerator.kt b/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/AddressGenerator.kt deleted file mode 100644 index c80521bf4a..0000000000 --- a/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/AddressGenerator.kt +++ /dev/null @@ -1,75 +0,0 @@ -package uk.gov.justice.digital.hmpps.data.generator - -import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.AddressStatus -import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.Person -import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddress -import java.time.LocalDate - -object AddressGenerator { - val ADDRESS_STATUS_MAIN = generateStatus("M") - val ADDRESS_STATUS_PREVIOUS = generateStatus("P") - val ADDRESS_STATUS_OTHER = generateStatus("O") - val ADDRESS_MAIN = generateAddress( - PersonGenerator.DEFAULT_PERSON, - ADDRESS_STATUS_MAIN, - buildingNumber = "21", - streetName = "Mantle Place", - town = "Hearth", - postcode = "H34 7TH" - ) - val ADDRESS_PREVIOUS = generateAddress( - PersonGenerator.DEFAULT_PERSON, - ADDRESS_STATUS_PREVIOUS, - buildingName = "Casa Anterior", - streetName = "Plaza de Espana", - county = "Seville", - postcode = "S3 11E", - startDate = LocalDate.now().minusDays(12), - endDate = LocalDate.now().minusDays(1) - ) - val ADDRESS_OTHER = generateAddress(PersonGenerator.DEFAULT_PERSON, ADDRESS_STATUS_OTHER) - val ADDRESS_DELETED = generateAddress( - PersonGenerator.DEFAULT_PERSON, - ADDRESS_STATUS_OTHER, - buildingNumber = "1", - streetName = "Deleted Close", - district = "Invisible", - softDeleted = true - ) - - fun generateStatus( - code: String, - description: String = "Description of $code", - id: Long = IdGenerator.getAndIncrement() - ) = AddressStatus(code, description, id) - - fun generateAddress( - person: Person, - status: AddressStatus, - buildingName: String? = null, - buildingNumber: String? = null, - streetName: String? = null, - district: String? = null, - town: String? = null, - county: String? = null, - postcode: String? = null, - startDate: LocalDate = LocalDate.now(), - endDate: LocalDate? = null, - softDeleted: Boolean = false, - id: Long = IdGenerator.getAndIncrement() - ) = PersonAddress( - person, - status, - buildingName, - buildingNumber, - streetName, - district, - town, - county, - postcode, - startDate, - endDate, - softDeleted, - id - ) -} diff --git a/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/CaseloadGenerator.kt b/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/CaseloadGenerator.kt index 8996b5872c..740bcba2ce 100644 --- a/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/CaseloadGenerator.kt +++ b/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/CaseloadGenerator.kt @@ -71,7 +71,7 @@ object CaseloadGenerator { roleCode = Caseload.CaseloadRole.ORDER_SUPERVISOR.value ) - val MANAGED_OFFENDER = generateManagedOffender(CASELOAD_ROLE_OM_1, STAFF1, ProviderGenerator.DEFAULT_TEAM) + val MANAGED_OFFENDER = generateManagedOffender(CASELOAD_ROLE_OM_1, STAFF1, DEFAULT_TEAM) fun generateCaseload( staff: Staff, diff --git a/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ProviderGenerator.kt b/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ProviderGenerator.kt index 953ea54dc6..9e437b55b7 100644 --- a/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ProviderGenerator.kt +++ b/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ProviderGenerator.kt @@ -100,42 +100,6 @@ object ProviderGenerator { id: Long = IdGenerator.getAndIncrement() ) = Team(code, description, telephone, emailAddress, district, addresses, startDate, endDate, id) - fun generateOfficeAddress( - officeLocation: OfficeLocation, - ldu: District - ) = OfficeAddress( - officeLocation.description, - officeLocation.buildingName, - officeLocation.buildingNumber, - officeLocation.streetName, - officeLocation.district, - officeLocation.townCity, - officeLocation.county, - officeLocation.postcode, - ldu.description, - officeLocation.telephoneNumber, - officeLocation.startDate, - officeLocation.endDate - ) - - fun generateLocation(location: OfficeLocation, ldu: District) = - OfficeLocation( - location.code, - location.description, - location.buildingName, - location.buildingNumber, - location.streetName, - location.district, - location.townCity, - location.county, - location.postcode, - location.telephoneNumber, - location.startDate, - location.endDate, - ldu, - location.id - ) - fun generateLocation( code: String, description: String, diff --git a/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/SentenceGenerator.kt b/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/SentenceGenerator.kt index 7d27c98882..48cda15019 100644 --- a/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/SentenceGenerator.kt +++ b/projects/create-and-vary-a-licence-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/SentenceGenerator.kt @@ -2,7 +2,6 @@ package uk.gov.justice.digital.hmpps.data.generator import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.Person import uk.gov.justice.digital.hmpps.integrations.delius.sentence.entity.* -import uk.gov.justice.digital.hmpps.set import java.time.LocalDate object SentenceGenerator { diff --git a/projects/create-and-vary-a-licence-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt b/projects/create-and-vary-a-licence-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt index 4b78100ed1..1fee31a8af 100644 --- a/projects/create-and-vary-a-licence-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt +++ b/projects/create-and-vary-a-licence-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt @@ -20,7 +20,6 @@ import uk.gov.justice.digital.hmpps.service.* import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.contentAsJson import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.withJson import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.withToken -import java.time.LocalDate @AutoConfigureMockMvc @SpringBootTest(webEnvironment = RANDOM_PORT) @@ -78,43 +77,6 @@ internal class IntegrationTest { ).andExpect(status().isNotFound) } - @Test - fun `can return all addresses for a crn`() { - val crn = PersonGenerator.DEFAULT_PERSON.crn - - val addresses = mockMvc - .perform(get("/probation-case/$crn/addresses").withToken()) - .andExpect(status().isOk) - .andReturn().response.contentAsJson>() - - assertThat(addresses.size, equalTo(2)) - assertThat( - addresses.first(), - equalTo( - Address.from( - buildingNumber = "21", - streetName = "Mantle Place", - town = "Hearth", - postcode = "H34 7TH", - from = LocalDate.now() - ) - ) - ) - assertThat( - addresses.last(), - equalTo( - Address.from( - buildingName = "Casa Anterior", - streetName = "Plaza de Espana", - county = "Seville", - postcode = "S3 11E", - from = LocalDate.now().minusDays(12), - to = LocalDate.now().minusDays(1) - ) - ) - ) - } - @Test fun `returns staff details`() { val username = StaffGenerator.DEFAULT_STAFF_USER.username diff --git a/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/Address.kt b/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/Address.kt deleted file mode 100644 index 8db543d3ba..0000000000 --- a/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/Address.kt +++ /dev/null @@ -1,37 +0,0 @@ -package uk.gov.justice.digital.hmpps.api.model - -import java.time.LocalDate - -data class Address( - val buildingName: String?, - val buildingNumber: String?, - val streetName: String?, - val district: String?, - val town: String?, - val county: String?, - val postcode: String?, - val from: LocalDate, - val to: LocalDate? -) { - companion object { - fun from( - buildingName: String? = null, - buildingNumber: String? = null, - streetName: String? = null, - district: String? = null, - town: String? = null, - county: String? = null, - postcode: String? = null, - from: LocalDate, - to: LocalDate? = null - ): Address? = - if ( - buildingName == null && buildingNumber == null && streetName == null && - district == null && town == null && county == null && postcode == null - ) { - null - } else { - Address(buildingName, buildingNumber, streetName, district, town, county, postcode, from, to) - } - } -} diff --git a/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/ProbationCaseResource.kt b/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/ProbationCaseResource.kt index 020ee77b3d..25394f26cd 100644 --- a/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/ProbationCaseResource.kt +++ b/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/ProbationCaseResource.kt @@ -5,22 +5,13 @@ import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController -import uk.gov.justice.digital.hmpps.api.model.Address import uk.gov.justice.digital.hmpps.api.model.Manager -import uk.gov.justice.digital.hmpps.service.AddressService import uk.gov.justice.digital.hmpps.service.ManagerService @RestController @RequestMapping("probation-case/{crn}") -class ProbationCaseResource( - private val responsibleManagerService: ManagerService, - private val addressService: AddressService -) { +class ProbationCaseResource(private val responsibleManagerService: ManagerService) { @PreAuthorize("hasRole('PROBATION_API__CVL__CASE_DETAIL')") @GetMapping("responsible-community-manager") fun findCommunityManager(@PathVariable crn: String): Manager = responsibleManagerService.findCommunityManager(crn) - - @PreAuthorize("hasRole('PROBATION_API__CVL__CASE_DETAIL')") - @GetMapping("addresses") - fun findAddresses(@PathVariable crn: String): List
= addressService.findAddresses(crn) } diff --git a/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/contact.entity/Contact.kt b/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/contact.entity/Contact.kt index ab4fa76898..57fb677220 100644 --- a/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/contact.entity/Contact.kt +++ b/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/contact.entity/Contact.kt @@ -1,17 +1,6 @@ package uk.gov.justice.digital.hmpps.integrations.delius.contact.entity -import jakarta.persistence.Column -import jakarta.persistence.Entity -import jakarta.persistence.EntityListeners -import jakarta.persistence.GeneratedValue -import jakarta.persistence.GenerationType -import jakarta.persistence.Id -import jakarta.persistence.JoinColumn -import jakarta.persistence.Lob -import jakarta.persistence.ManyToOne -import jakarta.persistence.SequenceGenerator -import jakarta.persistence.Table -import jakarta.persistence.Version +import jakarta.persistence.* import org.hibernate.annotations.Immutable import org.springframework.data.annotation.CreatedBy import org.springframework.data.annotation.CreatedDate @@ -89,7 +78,7 @@ class ContactType( val id: Long ) { companion object { - val LPOP = "LPOP" + const val LPOP = "LPOP" } } diff --git a/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/person/entity/PersonAddress.kt b/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/person/entity/PersonAddress.kt deleted file mode 100644 index d9c4355f9f..0000000000 --- a/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/person/entity/PersonAddress.kt +++ /dev/null @@ -1,69 +0,0 @@ -package uk.gov.justice.digital.hmpps.integrations.delius.person.entity - -import jakarta.persistence.Column -import jakarta.persistence.Entity -import jakarta.persistence.Id -import jakarta.persistence.JoinColumn -import jakarta.persistence.ManyToOne -import jakarta.persistence.Table -import org.hibernate.annotations.Immutable -import org.hibernate.annotations.SQLRestriction -import org.springframework.data.jpa.repository.JpaRepository -import java.time.LocalDate - -@Immutable -@Entity -@Table(name = "offender_address") -@SQLRestriction("soft_deleted = 0") -class PersonAddress( - - @ManyToOne - @JoinColumn(name = "offender_id") - val person: Person, - - @ManyToOne - @JoinColumn(name = "address_status_id") - val status: AddressStatus, - - @Column(name = "building_name") - val buildingName: String?, - @Column(name = "address_number") - val buildingNumber: String?, - @Column(name = "street_name") - val streetName: String?, - val district: String?, - @Column(name = "town_city") - val town: String?, - val county: String?, - val postcode: String?, - - val startDate: LocalDate, - val endDate: LocalDate?, - - @Column(columnDefinition = "number") - val softDeleted: Boolean, - - @Id - @Column(name = "offender_address_id") - val id: Long -) - -@Immutable -@Entity -@Table(name = "r_standard_reference_list") -class AddressStatus( - - @Column(name = "code_value") - val code: String, - - @Column(name = "code_description") - val description: String, - - @Id - @Column(name = "standard_reference_list_id") - val id: Long -) - -interface PersonAddressRepository : JpaRepository { - fun findAllByPersonCrnOrderByStartDateDesc(crn: String): List -} diff --git a/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/provider/entity/Provider.kt b/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/provider/entity/Provider.kt index 42c12ba8e1..6fa5589f3c 100644 --- a/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/provider/entity/Provider.kt +++ b/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/provider/entity/Provider.kt @@ -3,8 +3,6 @@ package uk.gov.justice.digital.hmpps.integrations.delius.provider.entity import jakarta.persistence.* import org.hibernate.annotations.Immutable import org.hibernate.annotations.SQLRestriction -import org.springframework.data.domain.Page -import org.springframework.data.domain.Pageable import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Query import uk.gov.justice.digital.hmpps.api.model.OfficeAddress diff --git a/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/sentence/entity/ReferenceData.kt b/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/sentence/entity/ReferenceData.kt index e476c15584..fc2b0ecee0 100644 --- a/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/sentence/entity/ReferenceData.kt +++ b/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/sentence/entity/ReferenceData.kt @@ -20,8 +20,8 @@ class LicenceConditionCategory( val id: Long ) { companion object { - val STANDARD_CATEGORY_CODE = "SL1" - val BESPOKE_CATEGORY_CODE = "BESP" + const val STANDARD_CATEGORY_CODE = "SL1" + const val BESPOKE_CATEGORY_CODE = "BESP" } } @@ -44,10 +44,10 @@ class ReferenceData( val id: Long ) { companion object { - val STANDARD_SUB_CATEGORY_CODE = "SL1" - val BESPOKE_SUB_CATEGORY_CODE = "NSTT9" - val INITIAL_ALLOCATION_CODE = "IN1" - val SENTENCE_EXPIRY_CODE = "SED" + const val STANDARD_SUB_CATEGORY_CODE = "SL1" + const val BESPOKE_SUB_CATEGORY_CODE = "NSTT9" + const val INITIAL_ALLOCATION_CODE = "IN1" + const val SENTENCE_EXPIRY_CODE = "SED" } } @@ -64,8 +64,8 @@ class Dataset( val id: Long ) { companion object { - val SUB_CATEGORY_CODE = "LICENCE CONDITION SUB CATEGORY" - val LM_ALLOCATION_REASON = "LM ALLOCATION REASON" + const val SUB_CATEGORY_CODE = "LICENCE CONDITION SUB CATEGORY" + const val LM_ALLOCATION_REASON = "LM ALLOCATION REASON" } } @@ -80,7 +80,7 @@ class TransferReason( val id: Long ) { companion object { - val DEFAULT_CODE = "COMPONENT" + const val DEFAULT_CODE = "COMPONENT" } } diff --git a/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/AddressService.kt b/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/AddressService.kt deleted file mode 100644 index b6cf20c925..0000000000 --- a/projects/create-and-vary-a-licence-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/AddressService.kt +++ /dev/null @@ -1,23 +0,0 @@ -package uk.gov.justice.digital.hmpps.service - -import org.springframework.stereotype.Service -import uk.gov.justice.digital.hmpps.api.model.Address -import uk.gov.justice.digital.hmpps.integrations.delius.person.entity.PersonAddressRepository - -@Service -class AddressService(private val personAddressRepository: PersonAddressRepository) { - fun findAddresses(crn: String): List
= - personAddressRepository.findAllByPersonCrnOrderByStartDateDesc(crn).mapNotNull { - Address.from( - it.buildingName, - it.buildingNumber, - it.streetName, - it.district, - it.town, - it.county, - it.postcode, - it.startDate, - it.endDate - ) - } -} diff --git a/projects/create-and-vary-a-licence-and-delius/src/main/resources/application.yml b/projects/create-and-vary-a-licence-and-delius/src/main/resources/application.yml index 040d408f48..d8f2115e56 100644 --- a/projects/create-and-vary-a-licence-and-delius/src/main/resources/application.yml +++ b/projects/create-and-vary-a-licence-and-delius/src/main/resources/application.yml @@ -42,6 +42,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/custody-key-dates-and-delius/deploy/values.yaml b/projects/custody-key-dates-and-delius/deploy/values.yaml index cfff165e92..f5b0792101 100644 --- a/projects/custody-key-dates-and-delius/deploy/values.yaml +++ b/projects/custody-key-dates-and-delius/deploy/values.yaml @@ -1,4 +1,5 @@ generic-service: + productId: HMPPS518 nameOverride: custody-key-dates-and-delius serviceAccountName: custody-key-dates-and-delius diff --git a/projects/custody-key-dates-and-delius/src/main/resources/application.yml b/projects/custody-key-dates-and-delius/src/main/resources/application.yml index df7e2023b5..e4eba09ff2 100644 --- a/projects/custody-key-dates-and-delius/src/main/resources/application.yml +++ b/projects/custody-key-dates-and-delius/src/main/resources/application.yml @@ -36,6 +36,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/projects/domain-events-and-delius/deploy/values.yaml b/projects/domain-events-and-delius/deploy/values.yaml index 2007c422ec..b7d7566446 100644 --- a/projects/domain-events-and-delius/deploy/values.yaml +++ b/projects/domain-events-and-delius/deploy/values.yaml @@ -1,4 +1,5 @@ generic-service: + productId: HMPPS518 nameOverride: domain-events-and-delius serviceAccountName: domain-events-and-delius replicaCount: 1 diff --git a/projects/domain-events-and-delius/src/main/resources/application.yml b/projects/domain-events-and-delius/src/main/resources/application.yml index ce10fde721..0c3e4c3870 100644 --- a/projects/domain-events-and-delius/src/main/resources/application.yml +++ b/projects/domain-events-and-delius/src/main/resources/application.yml @@ -29,6 +29,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/projects/dps-and-delius/deploy/values.yaml b/projects/dps-and-delius/deploy/values.yaml index 9b0e6e4cbb..f77ef9531b 100644 --- a/projects/dps-and-delius/deploy/values.yaml +++ b/projects/dps-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: dps-and-delius image: diff --git a/projects/dps-and-delius/src/main/resources/application.yml b/projects/dps-and-delius/src/main/resources/application.yml index fd5f417427..09c1df8cd2 100644 --- a/projects/dps-and-delius/src/main/resources/application.yml +++ b/projects/dps-and-delius/src/main/resources/application.yml @@ -31,6 +31,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/effective-proposal-framework-and-delius/deploy/values.yaml b/projects/effective-proposal-framework-and-delius/deploy/values.yaml index 1c8c9c2a3d..cb68b030f3 100644 --- a/projects/effective-proposal-framework-and-delius/deploy/values.yaml +++ b/projects/effective-proposal-framework-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: effective-proposal-framework-and-delius image: diff --git a/projects/effective-proposal-framework-and-delius/src/main/resources/application.yml b/projects/effective-proposal-framework-and-delius/src/main/resources/application.yml index caaa030ffc..713057750b 100644 --- a/projects/effective-proposal-framework-and-delius/src/main/resources/application.yml +++ b/projects/effective-proposal-framework-and-delius/src/main/resources/application.yml @@ -28,6 +28,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/external-api-and-delius/deploy/values.yaml b/projects/external-api-and-delius/deploy/values.yaml index 371544c3a5..7613c5bb9e 100644 --- a/projects/external-api-and-delius/deploy/values.yaml +++ b/projects/external-api-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: external-api-and-delius image: diff --git a/projects/external-api-and-delius/src/main/resources/application.yml b/projects/external-api-and-delius/src/main/resources/application.yml index d8beb1aaca..366d535be3 100644 --- a/projects/external-api-and-delius/src/main/resources/application.yml +++ b/projects/external-api-and-delius/src/main/resources/application.yml @@ -32,6 +32,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/feature-flags/README.md b/projects/feature-flags/README.md new file mode 100644 index 0000000000..21a7912c06 --- /dev/null +++ b/projects/feature-flags/README.md @@ -0,0 +1,3 @@ +# Feature Flags + +A self-hosted instance of [Flipt](https://www.flipt.io/), for controlling feature flags. diff --git a/projects/feature-flags/container/Dockerfile b/projects/feature-flags/container/Dockerfile index 0ba618d9fa..e9fa9c3c54 100644 --- a/projects/feature-flags/container/Dockerfile +++ b/projects/feature-flags/container/Dockerfile @@ -1,4 +1,4 @@ -FROM ghcr.io/flipt-io/flipt:v1.42.0 +FROM ghcr.io/flipt-io/flipt:v1.43.0 # Run any pending migrations on startup CMD ["sh", "-c", "./flipt migrate && ./flipt"] \ No newline at end of file diff --git a/projects/feature-flags/deploy/values.yaml b/projects/feature-flags/deploy/values.yaml index 2293b59e7f..65414a6ade 100644 --- a/projects/feature-flags/deploy/values.yaml +++ b/projects/feature-flags/deploy/values.yaml @@ -1,4 +1,5 @@ generic-service: + productId: HMPPS518 nameOverride: feature-flags image: diff --git a/projects/hdc-licences-and-delius/deploy/values.yaml b/projects/hdc-licences-and-delius/deploy/values.yaml index 82ff948e25..a2bc3179b4 100644 --- a/projects/hdc-licences-and-delius/deploy/values.yaml +++ b/projects/hdc-licences-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: hdc-licences-and-delius image: diff --git a/projects/hdc-licences-and-delius/src/main/resources/application.yml b/projects/hdc-licences-and-delius/src/main/resources/application.yml index b5cf5d4cd4..c8fffa8dfd 100644 --- a/projects/hdc-licences-and-delius/src/main/resources/application.yml +++ b/projects/hdc-licences-and-delius/src/main/resources/application.yml @@ -32,6 +32,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/hmpps-auth-and-delius/deploy/values.yaml b/projects/hmpps-auth-and-delius/deploy/values.yaml index 9e2eb1ddbc..bae521dc4e 100644 --- a/projects/hmpps-auth-and-delius/deploy/values.yaml +++ b/projects/hmpps-auth-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: hmpps-auth-and-delius image: diff --git a/projects/hmpps-auth-and-delius/src/main/resources/application.yml b/projects/hmpps-auth-and-delius/src/main/resources/application.yml index 3a02a34ab5..df99652966 100644 --- a/projects/hmpps-auth-and-delius/src/main/resources/application.yml +++ b/projects/hmpps-auth-and-delius/src/main/resources/application.yml @@ -32,6 +32,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/make-recall-decisions-and-delius/deploy/values.yaml b/projects/make-recall-decisions-and-delius/deploy/values.yaml index 62e44ab540..a129cb578e 100644 --- a/projects/make-recall-decisions-and-delius/deploy/values.yaml +++ b/projects/make-recall-decisions-and-delius/deploy/values.yaml @@ -1,4 +1,5 @@ generic-service: + productId: HMPPS518 nameOverride: make-recall-decisions-and-delius serviceAccountName: make-recall-decisions-and-delius diff --git a/projects/make-recall-decisions-and-delius/src/main/resources/application.yml b/projects/make-recall-decisions-and-delius/src/main/resources/application.yml index 2eda02bd09..dccfc5c149 100644 --- a/projects/make-recall-decisions-and-delius/src/main/resources/application.yml +++ b/projects/make-recall-decisions-and-delius/src/main/resources/application.yml @@ -44,6 +44,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/manage-offences-and-delius/deploy/values.yaml b/projects/manage-offences-and-delius/deploy/values.yaml index 478f99246f..ff441b7eb4 100644 --- a/projects/manage-offences-and-delius/deploy/values.yaml +++ b/projects/manage-offences-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: manage-offences-and-delius serviceAccountName: manage-offences-and-delius diff --git a/projects/manage-offences-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt b/projects/manage-offences-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt index 0dd78d7c25..fb01a1a3a5 100644 --- a/projects/manage-offences-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt +++ b/projects/manage-offences-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt @@ -28,8 +28,8 @@ class DataLoader( with(entityManager) { merge(DataGenerator.COURT_CATEGORY_SET) merge(DataGenerator.COURT_CATEGORY) - merge(DataGenerator.EXISTING_OFFENCE) - merge(DataGenerator.HL_OFFENCE) + merge(DataGenerator.EXISTING_DETAILED_OFFENCE) + merge(DataGenerator.HIGH_LEVEL_OFFENCE) } } } diff --git a/projects/manage-offences-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/DataGenerator.kt b/projects/manage-offences-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/DataGenerator.kt index dfeac9bbb3..c0b70142c8 100644 --- a/projects/manage-offences-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/DataGenerator.kt +++ b/projects/manage-offences-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/DataGenerator.kt @@ -7,15 +7,10 @@ import uk.gov.justice.digital.hmpps.entity.ReferenceOffence import java.time.LocalDate object DataGenerator { - val HL_OFFENCE = generateReferenceOffence( - code = "09100", - mainCategoryCode = "091", - subCategoryCode = "00", - ogrsOffenceCategoryId = 298456347L - ) val COURT_CATEGORY_SET = ReferenceDataSet(IdGenerator.getAndIncrement(), "COURT CATEGORY") val COURT_CATEGORY = ReferenceData(IdGenerator.getAndIncrement(), "CS", "Summary Non-motoring", COURT_CATEGORY_SET) - val EXISTING_OFFENCE = DetailedOffence( + + val EXISTING_DETAILED_OFFENCE = DetailedOffence( id = IdGenerator.getAndIncrement(), code = "AB06001", description = "Obstruct person acting in execution of the regulations - 09155", @@ -27,6 +22,19 @@ object DataGenerator { endDate = null ) + val HIGH_LEVEL_OFFENCE = generateReferenceOffence( + code = "09100", + mainCategoryCode = "091", + subCategoryCode = "00", + ogrsOffenceCategoryId = 1L + ) + val EXISTING_OFFENCE = generateReferenceOffence( + code = "09155", + mainCategoryCode = "091", + subCategoryCode = "55", + ogrsOffenceCategoryId = 2L + ) + fun generateReferenceOffence( code: String, description: String = "Description of $code", diff --git a/projects/manage-offences-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt b/projects/manage-offences-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt index 741b80b7d5..8f0dec3d5d 100644 --- a/projects/manage-offences-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt +++ b/projects/manage-offences-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt @@ -14,6 +14,7 @@ import uk.gov.justice.digital.hmpps.entity.OffenceRepository import uk.gov.justice.digital.hmpps.flags.FeatureFlags import uk.gov.justice.digital.hmpps.message.Notification import uk.gov.justice.digital.hmpps.messaging.FF_CREATE_OFFENCE +import uk.gov.justice.digital.hmpps.messaging.FF_UPDATE_OFFENCE import uk.gov.justice.digital.hmpps.messaging.HmppsChannelManager import uk.gov.justice.digital.hmpps.resourceloader.ResourceLoader import uk.gov.justice.digital.hmpps.telemetry.TelemetryService @@ -38,6 +39,7 @@ internal class IntegrationTest { @Test fun `update offence code`() { whenever(featureFlags.enabled(FF_CREATE_OFFENCE)).thenReturn(true) + whenever(featureFlags.enabled(FF_UPDATE_OFFENCE)).thenReturn(true) val notification = Notification(ResourceLoader.event("offence-changed")) channelManager.getChannel(queueName).publishAndWait(notification) @@ -59,7 +61,7 @@ internal class IntegrationTest { val referenceOffence = offenceRepository.findByCode("09155") assertNotNull(referenceOffence) - assertThat(referenceOffence?.description).isEqualTo("Obstructing a person home office description") + assertThat(referenceOffence?.description).isEqualTo("Obstructing a person home office description - 09155") assertThat(referenceOffence?.mainCategoryCode).isEqualTo("091") assertThat(referenceOffence?.subCategoryCode).isEqualTo("55") assertThat(referenceOffence?.schedule15ViolentOffence).isEqualTo(true) diff --git a/projects/manage-offences-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/config/IgnoredOffences.kt b/projects/manage-offences-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/config/IgnoredOffences.kt new file mode 100644 index 0000000000..3aa2fa4f41 --- /dev/null +++ b/projects/manage-offences-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/config/IgnoredOffences.kt @@ -0,0 +1,19 @@ +package uk.gov.justice.digital.hmpps.config + +import uk.gov.justice.digital.hmpps.client.Offence + +data class IgnoredOffence( + val reason: String, + val matches: (offence: Offence) -> Boolean +) { + companion object { + val IGNORED_OFFENCES = listOf( + IgnoredOffence("Home Office Code is 'Not Known'") { + it.homeOfficeCode == "22222" + }, + IgnoredOffence("CJS Code suffix is 500 or above") { + it.code.takeLast(3).toIntOrNull()?.let { suffix -> suffix >= 500 } == true + }, + ) + } +} \ No newline at end of file diff --git a/projects/manage-offences-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt b/projects/manage-offences-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt index a5fdacb01a..c93e912eaa 100644 --- a/projects/manage-offences-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt +++ b/projects/manage-offences-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/messaging/Handler.kt @@ -4,6 +4,7 @@ import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional import uk.gov.justice.digital.hmpps.client.ManageOffencesClient import uk.gov.justice.digital.hmpps.client.Offence +import uk.gov.justice.digital.hmpps.config.IgnoredOffence.Companion.IGNORED_OFFENCES import uk.gov.justice.digital.hmpps.converter.NotificationConverter import uk.gov.justice.digital.hmpps.entity.DetailedOffence import uk.gov.justice.digital.hmpps.entity.OffenceRepository @@ -20,6 +21,7 @@ import uk.gov.justice.digital.hmpps.telemetry.TelemetryService import uk.gov.justice.digital.hmpps.telemetry.notificationReceived const val FF_CREATE_OFFENCE = "manage-offences-create-offence" +const val FF_UPDATE_OFFENCE = "manage-offences-update-offence" @Component class Handler( @@ -38,18 +40,17 @@ class Handler( val offence = manageOffencesClient.getOffence(notification.message.offenceCode) + IGNORED_OFFENCES.firstOrNull { it.matches(offence) }?.let { + telemetryService.trackEvent("OffenceCodeIgnored", offence.telemetry + mapOf("reason" to it.reason)) + return + } + val isNew = mergeDetailedOffence(offence) if (featureFlags.enabled(FF_CREATE_OFFENCE)) { mergeReferenceOffence(offence) } - telemetryService.trackEvent( - if (isNew) "OffenceCodeCreated" else "OffenceCodeUpdated", - listOfNotNull( - "offenceCode" to offence.code, - offence.homeOfficeCode?.let { "homeOfficeCode" to it } - ).toMap() - ) + telemetryService.trackEvent(if (isNew) "OffenceCodeCreated" else "OffenceCodeUpdated", offence.telemetry) } private fun mergeDetailedOffence(offence: Offence): Boolean { @@ -61,6 +62,7 @@ class Handler( private fun mergeReferenceOffence(offence: Offence) { if (offence.homeOfficeCode == null) return val existingEntity = offenceRepository.findByCode(offence.homeOfficeCode!!) + if (existingEntity != null && !featureFlags.enabled(FF_UPDATE_OFFENCE)) return val highLevelOffence = offenceRepository.getByCode(offence.highLevelCode!!) offenceRepository.save(existingEntity.mergeWith(offence.toReferenceOffence(highLevelOffence))) } @@ -81,7 +83,7 @@ class Handler( private fun Offence.toReferenceOffence(highLevelOffence: ReferenceOffence) = ReferenceOffence( code = homeOfficeCode!!, - description = homeOfficeDescription!!, + description = "$homeOfficeDescription - $homeOfficeCode", mainCategoryCode = mainCategoryCode!!, selectable = false, mainCategoryDescription = highLevelOffence.description.take(200), @@ -123,3 +125,9 @@ class Handler( } val HmppsDomainEvent.offenceCode get() = additionalInformation["offenceCode"] as String + +val Offence.telemetry + get() = listOfNotNull( + "offenceCode" to code, + homeOfficeCode?.let { "homeOfficeCode" to it } + ).toMap() \ No newline at end of file diff --git a/projects/manage-offences-and-delius/src/main/resources/application.yml b/projects/manage-offences-and-delius/src/main/resources/application.yml index dc36e4f40c..48ecbbc9fb 100644 --- a/projects/manage-offences-and-delius/src/main/resources/application.yml +++ b/projects/manage-offences-and-delius/src/main/resources/application.yml @@ -36,6 +36,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/projects/manage-offences-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt b/projects/manage-offences-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt index 2ad732ed52..830b6c11f7 100644 --- a/projects/manage-offences-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt +++ b/projects/manage-offences-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/messaging/HandlerTest.kt @@ -8,14 +8,14 @@ import org.junit.jupiter.api.extension.ExtendWith import org.mockito.InjectMocks import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension -import org.mockito.kotlin.check -import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever +import org.mockito.kotlin.* import uk.gov.justice.digital.hmpps.client.ManageOffencesClient import uk.gov.justice.digital.hmpps.client.Offence import uk.gov.justice.digital.hmpps.converter.NotificationConverter import uk.gov.justice.digital.hmpps.data.generator.DataGenerator.COURT_CATEGORY +import uk.gov.justice.digital.hmpps.data.generator.DataGenerator.EXISTING_DETAILED_OFFENCE import uk.gov.justice.digital.hmpps.data.generator.DataGenerator.EXISTING_OFFENCE +import uk.gov.justice.digital.hmpps.data.generator.DataGenerator.HIGH_LEVEL_OFFENCE import uk.gov.justice.digital.hmpps.entity.OffenceRepository import uk.gov.justice.digital.hmpps.exception.NotFoundException import uk.gov.justice.digital.hmpps.flags.FeatureFlags @@ -64,67 +64,134 @@ internal class HandlerTest { .run { assertThat(message, equalTo("Court category with code of CS not found")) } } + @Test + fun `home office codes of 22222 are ignored`() { + whenever(manageOffencesClient.getOffence(any())).thenReturn(offence(homeOfficeCode = "222/22")) + + handler.handle(Notification(ResourceLoader.event("offence-changed"))) + + verify(telemetryService).trackEvent( + "OffenceCodeIgnored", + mapOf( + "offenceCode" to "AB12345", + "homeOfficeCode" to "22222", + "reason" to "Home Office Code is 'Not Known'" + ), + mapOf() + ) + } + + @Test + fun `cjs codes ending with a number of 500 or above are ignored`() { + whenever(manageOffencesClient.getOffence(any())).thenReturn(offence(code = "AB12500")) + + handler.handle(Notification(ResourceLoader.event("offence-changed"))) + + verify(telemetryService).trackEvent( + "OffenceCodeIgnored", + mapOf( + "offenceCode" to "AB12500", + "homeOfficeCode" to "09155", + "reason" to "CJS Code suffix is 500 or above" + ), + mapOf() + ) + } + @Test fun `offence is created`() { - whenever(featureFlags.enabled(FF_CREATE_OFFENCE)).thenReturn(false) + whenever(featureFlags.enabled(FF_CREATE_OFFENCE)).thenReturn(true) val notification = Notification(ResourceLoader.event("offence-changed")) - val offenceCode = notification.message.offenceCode - whenever(manageOffencesClient.getOffence(offenceCode)).thenReturn(offence(offenceCode)) - whenever(referenceDataRepository.findByCodeAndSetName(COURT_CATEGORY.code, COURT_CATEGORY.set.name)).thenReturn( - COURT_CATEGORY - ) + val offence = offence(notification.message.offenceCode) + whenever(manageOffencesClient.getOffence(offence.code)).thenReturn(offence) + whenever(referenceDataRepository.findByCodeAndSetName(COURT_CATEGORY.code, COURT_CATEGORY.set.name)) + .thenReturn(COURT_CATEGORY) + whenever(offenceRepository.findByCode(any())).thenReturn(null) + whenever(offenceRepository.findByCode(HIGH_LEVEL_OFFENCE.code)).thenReturn(HIGH_LEVEL_OFFENCE) handler.handle(notification) verify(telemetryService).notificationReceived(notification) - verify(detailedOffenceRepository).save( - check { - assertThat(it.id, equalTo(0)) - assertThat(it.code, equalTo(offenceCode)) - assertThat(it.category, equalTo(COURT_CATEGORY)) - } - ) + verify(detailedOffenceRepository).save(check { + assertThat(it.id, equalTo(0)) + assertThat(it.code, equalTo(offence.code)) + assertThat(it.category, equalTo(COURT_CATEGORY)) + }) + verify(offenceRepository).save(check { + assertThat(it.id, equalTo(0)) + assertThat(it.code, equalTo(offence.homeOfficeCode)) + }) verify(telemetryService).trackEvent( "OffenceCodeCreated", - mapOf("offenceCode" to offenceCode, "homeOfficeCode" to "01234"), + mapOf("offenceCode" to offence.code, "homeOfficeCode" to "09155"), mapOf() ) } @Test fun `offence is updated`() { - whenever(featureFlags.enabled(FF_CREATE_OFFENCE)).thenReturn(false) + whenever(featureFlags.enabled(FF_CREATE_OFFENCE)).thenReturn(true) + whenever(featureFlags.enabled(FF_UPDATE_OFFENCE)).thenReturn(true) val notification = Notification(ResourceLoader.event("offence-changed")) - val offenceCode = notification.message.offenceCode - whenever(manageOffencesClient.getOffence(offenceCode)).thenReturn(offence(notification.message.offenceCode)) - whenever(referenceDataRepository.findByCodeAndSetName(COURT_CATEGORY.code, COURT_CATEGORY.set.name)).thenReturn( - COURT_CATEGORY + val offence = offence(notification.message.offenceCode) + whenever(manageOffencesClient.getOffence(offence.code)).thenReturn(offence) + whenever(referenceDataRepository.findByCodeAndSetName(COURT_CATEGORY.code, COURT_CATEGORY.set.name)) + .thenReturn(COURT_CATEGORY) + whenever(offenceRepository.findByCode(HIGH_LEVEL_OFFENCE.code)).thenReturn(HIGH_LEVEL_OFFENCE) + whenever(offenceRepository.findByCode(EXISTING_OFFENCE.code)).thenReturn(EXISTING_OFFENCE) + whenever(detailedOffenceRepository.findByCode(EXISTING_DETAILED_OFFENCE.code)).thenReturn( + EXISTING_DETAILED_OFFENCE ) - whenever(detailedOffenceRepository.findByCode(EXISTING_OFFENCE.code)).thenReturn(EXISTING_OFFENCE) handler.handle(notification) verify(telemetryService).notificationReceived(notification) - verify(detailedOffenceRepository).save( - check { - assertThat(it.id, equalTo(EXISTING_OFFENCE.id)) - assertThat(it.code, equalTo(offenceCode)) - assertThat(it.category, equalTo(COURT_CATEGORY)) - } - ) + verify(detailedOffenceRepository).save(check { + assertThat(it.id, equalTo(EXISTING_DETAILED_OFFENCE.id)) + assertThat(it.code, equalTo(offence.code)) + assertThat(it.category, equalTo(COURT_CATEGORY)) + }) + verify(offenceRepository).save(check { + assertThat(it.id, equalTo(EXISTING_OFFENCE.id)) + assertThat(it.code, equalTo(offence.homeOfficeCode)) + }) verify(telemetryService).trackEvent( "OffenceCodeUpdated", - mapOf("offenceCode" to offenceCode, "homeOfficeCode" to "01234"), + mapOf("offenceCode" to offence.code, "homeOfficeCode" to "09155"), mapOf() ) } - private fun offence(code: String) = Offence( + @Test + fun `offence is not updated when feature flag is disabled`() { + whenever(featureFlags.enabled(FF_CREATE_OFFENCE)).thenReturn(true) + whenever(featureFlags.enabled(FF_UPDATE_OFFENCE)).thenReturn(false) + val notification = Notification(ResourceLoader.event("offence-changed")) + val offence = offence(notification.message.offenceCode) + whenever(manageOffencesClient.getOffence(offence.code)).thenReturn(offence) + whenever(referenceDataRepository.findByCodeAndSetName(COURT_CATEGORY.code, COURT_CATEGORY.set.name)) + .thenReturn(COURT_CATEGORY) + whenever(offenceRepository.findByCode(EXISTING_OFFENCE.code)).thenReturn(EXISTING_OFFENCE) + whenever(detailedOffenceRepository.findByCode(EXISTING_DETAILED_OFFENCE.code)).thenReturn( + EXISTING_DETAILED_OFFENCE + ) + + handler.handle(notification) + + verify(offenceRepository, never()).save(any()) + verify(detailedOffenceRepository).save(check { + assertThat(it.id, equalTo(EXISTING_DETAILED_OFFENCE.id)) + assertThat(it.code, equalTo(offence.code)) + assertThat(it.category, equalTo(COURT_CATEGORY)) + }) + } + + private fun offence(code: String = "AB12345", homeOfficeCode: String = "091/55") = Offence( code = code, description = "some offence", offenceType = COURT_CATEGORY.code, startDate = LocalDate.now(), - homeOfficeStatsCode = "012/34", + homeOfficeStatsCode = homeOfficeCode, homeOfficeDescription = "Some Offence Description", ) } diff --git a/projects/manage-pom-cases-and-delius/deploy/values.yaml b/projects/manage-pom-cases-and-delius/deploy/values.yaml index 3798319db2..8cfb676c4e 100644 --- a/projects/manage-pom-cases-and-delius/deploy/values.yaml +++ b/projects/manage-pom-cases-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: manage-pom-cases-and-delius serviceAccountName: manage-pom-cases-and-delius diff --git a/projects/manage-pom-cases-and-delius/src/main/resources/application.yml b/projects/manage-pom-cases-and-delius/src/main/resources/application.yml index e6e54d4254..880d21e87f 100644 --- a/projects/manage-pom-cases-and-delius/src/main/resources/application.yml +++ b/projects/manage-pom-cases-and-delius/src/main/resources/application.yml @@ -42,6 +42,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/manage-supervision-and-delius/deploy/values.yaml b/projects/manage-supervision-and-delius/deploy/values.yaml index 82c19f2d9f..e44cd701de 100644 --- a/projects/manage-supervision-and-delius/deploy/values.yaml +++ b/projects/manage-supervision-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: manage-supervision-and-delius image: diff --git a/projects/manage-supervision-and-delius/src/main/resources/application.yml b/projects/manage-supervision-and-delius/src/main/resources/application.yml index 5243c4332c..da79a3f1ec 100644 --- a/projects/manage-supervision-and-delius/src/main/resources/application.yml +++ b/projects/manage-supervision-and-delius/src/main/resources/application.yml @@ -34,6 +34,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/manage-supervision-and-oasys/deploy/values.yaml b/projects/manage-supervision-and-oasys/deploy/values.yaml index a1d859ed1a..3862df6e6e 100644 --- a/projects/manage-supervision-and-oasys/deploy/values.yaml +++ b/projects/manage-supervision-and-oasys/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: manage-supervision-and-oasys image: diff --git a/projects/manage-supervision-and-oasys/src/main/resources/application.yml b/projects/manage-supervision-and-oasys/src/main/resources/application.yml index 469b8df5ad..1c24c65ea3 100644 --- a/projects/manage-supervision-and-oasys/src/main/resources/application.yml +++ b/projects/manage-supervision-and-oasys/src/main/resources/application.yml @@ -23,6 +23,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/projects/oasys-and-delius/deploy/values.yaml b/projects/oasys-and-delius/deploy/values.yaml index 7f1cfb3fa1..52a7f511cc 100644 --- a/projects/oasys-and-delius/deploy/values.yaml +++ b/projects/oasys-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: oasys-and-delius image: diff --git a/projects/oasys-and-delius/src/main/resources/application.yml b/projects/oasys-and-delius/src/main/resources/application.yml index ba547611a6..f1592f5579 100644 --- a/projects/oasys-and-delius/src/main/resources/application.yml +++ b/projects/oasys-and-delius/src/main/resources/application.yml @@ -28,6 +28,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/offender-events-and-delius/deploy/values.yaml b/projects/offender-events-and-delius/deploy/values.yaml index 82e048f3d9..4a37632e7f 100644 --- a/projects/offender-events-and-delius/deploy/values.yaml +++ b/projects/offender-events-and-delius/deploy/values.yaml @@ -1,4 +1,5 @@ generic-service: + productId: HMPPS518 nameOverride: offender-events-and-delius serviceAccountName: offender-events-and-delius replicaCount: 1 diff --git a/projects/offender-events-and-delius/src/main/resources/application.yml b/projects/offender-events-and-delius/src/main/resources/application.yml index 069dc4177b..361a42c772 100644 --- a/projects/offender-events-and-delius/src/main/resources/application.yml +++ b/projects/offender-events-and-delius/src/main/resources/application.yml @@ -26,6 +26,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/projects/opd-and-delius/deploy/values.yaml b/projects/opd-and-delius/deploy/values.yaml index e187810e19..4bca683217 100644 --- a/projects/opd-and-delius/deploy/values.yaml +++ b/projects/opd-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: opd-and-delius serviceAccountName: opd-and-delius diff --git a/projects/opd-and-delius/src/main/resources/application.yml b/projects/opd-and-delius/src/main/resources/application.yml index 2ba93971cc..f8d0ee6646 100644 --- a/projects/opd-and-delius/src/main/resources/application.yml +++ b/projects/opd-and-delius/src/main/resources/application.yml @@ -26,6 +26,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/projects/pathfinder-and-delius/deploy/values.yaml b/projects/pathfinder-and-delius/deploy/values.yaml index 5d732bc329..d83bd97889 100644 --- a/projects/pathfinder-and-delius/deploy/values.yaml +++ b/projects/pathfinder-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: pathfinder-and-delius image: diff --git a/projects/pathfinder-and-delius/src/main/resources/application.yml b/projects/pathfinder-and-delius/src/main/resources/application.yml index beca8e6d65..315167d1b0 100644 --- a/projects/pathfinder-and-delius/src/main/resources/application.yml +++ b/projects/pathfinder-and-delius/src/main/resources/application.yml @@ -32,6 +32,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/person-search-index-from-delius/deploy/values.yaml b/projects/person-search-index-from-delius/deploy/values.yaml index 2051776ba5..61077faf1e 100644 --- a/projects/person-search-index-from-delius/deploy/values.yaml +++ b/projects/person-search-index-from-delius/deploy/values.yaml @@ -1,4 +1,5 @@ generic-service: + productId: HMPPS518 nameOverride: person-search-index-from-delius serviceAccountName: person-search-index-from-delius resources: diff --git a/projects/pre-sentence-reports-to-delius/deploy/values.yaml b/projects/pre-sentence-reports-to-delius/deploy/values.yaml index ec6556985c..eed892ac2a 100644 --- a/projects/pre-sentence-reports-to-delius/deploy/values.yaml +++ b/projects/pre-sentence-reports-to-delius/deploy/values.yaml @@ -1,4 +1,5 @@ generic-service: + productId: HMPPS518 nameOverride: pre-sentence-reports-to-delius serviceAccountName: pre-sentence-reports-to-delius diff --git a/projects/pre-sentence-reports-to-delius/src/main/resources/application.yml b/projects/pre-sentence-reports-to-delius/src/main/resources/application.yml index 3450fc220d..c083740cca 100644 --- a/projects/pre-sentence-reports-to-delius/src/main/resources/application.yml +++ b/projects/pre-sentence-reports-to-delius/src/main/resources/application.yml @@ -39,6 +39,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/projects/prison-case-notes-to-probation/deploy/values.yaml b/projects/prison-case-notes-to-probation/deploy/values.yaml index bff4152a60..67d8c16a8b 100644 --- a/projects/prison-case-notes-to-probation/deploy/values.yaml +++ b/projects/prison-case-notes-to-probation/deploy/values.yaml @@ -2,6 +2,7 @@ # Values here are the same across all environments # An additional set of default values can be found in templates/helm-defaults.yml, which is the same across all projects generic-service: + productId: HMPPS518 nameOverride: prison-case-notes-to-probation serviceAccountName: prison-case-notes-to-probation diff --git a/projects/prison-case-notes-to-probation/src/main/resources/application.yml b/projects/prison-case-notes-to-probation/src/main/resources/application.yml index 4e2f87ac1f..410b239470 100644 --- a/projects/prison-case-notes-to-probation/src/main/resources/application.yml +++ b/projects/prison-case-notes-to-probation/src/main/resources/application.yml @@ -36,6 +36,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + logging.level: org.hibernate.engine.jdbc.spi.SqlExceptionHelper: OFF diff --git a/projects/prison-custody-status-to-delius/deploy/values.yaml b/projects/prison-custody-status-to-delius/deploy/values.yaml index 5cbad2e754..f196a88520 100644 --- a/projects/prison-custody-status-to-delius/deploy/values.yaml +++ b/projects/prison-custody-status-to-delius/deploy/values.yaml @@ -1,4 +1,5 @@ generic-service: + productId: HMPPS518 nameOverride: prison-custody-status-to-delius serviceAccountName: prison-custody-status-to-delius diff --git a/projects/prison-custody-status-to-delius/src/main/resources/application.yml b/projects/prison-custody-status-to-delius/src/main/resources/application.yml index a40791a758..c0fae4bf0b 100644 --- a/projects/prison-custody-status-to-delius/src/main/resources/application.yml +++ b/projects/prison-custody-status-to-delius/src/main/resources/application.yml @@ -39,6 +39,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/prison-education-and-delius/deploy/values.yaml b/projects/prison-education-and-delius/deploy/values.yaml index 6aadf16fb9..114353c04a 100644 --- a/projects/prison-education-and-delius/deploy/values.yaml +++ b/projects/prison-education-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: prison-education-and-delius image: diff --git a/projects/prison-education-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt b/projects/prison-education-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt index cbc057b26b..8dbbd9b566 100644 --- a/projects/prison-education-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt +++ b/projects/prison-education-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt @@ -30,6 +30,8 @@ class DataLoader( persist(DataGenerator.STAFF_WITH_USER) persist(DataGenerator.STAFF_WITH_USER.user) persist(DataGenerator.COMMUNITY_MANAGER_WITH_USER) + persist(DataGenerator.MAIN_ADDRESS_TYPE) + persist(DataGenerator.MAIN_ADDRESS) } } } diff --git a/projects/prison-education-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/DataGenerator.kt b/projects/prison-education-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/DataGenerator.kt index d830f80d88..f780088163 100644 --- a/projects/prison-education-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/DataGenerator.kt +++ b/projects/prison-education-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/DataGenerator.kt @@ -1,9 +1,6 @@ package uk.gov.justice.digital.hmpps.data.generator -import uk.gov.justice.digital.hmpps.entity.CommunityManager -import uk.gov.justice.digital.hmpps.entity.Person -import uk.gov.justice.digital.hmpps.entity.Staff -import uk.gov.justice.digital.hmpps.entity.UserDetails +import uk.gov.justice.digital.hmpps.entity.* import uk.gov.justice.digital.hmpps.set object DataGenerator { @@ -13,7 +10,25 @@ object DataGenerator { val STAFF_WITH_USER = Staff(id = IdGenerator.getAndIncrement(), forename = "Test", surname = "User", user = null) .set(Staff::user) { UserDetails(id = IdGenerator.getAndIncrement(), username = "TestUser", staff = it) } - val COMMUNITY_MANAGER = CommunityManager(id = IdGenerator.getAndIncrement(), personId = PERSON.id, staff = STAFF) + val COMMUNITY_MANAGER = CommunityManager(id = IdGenerator.getAndIncrement(), person = PERSON, staff = STAFF) val COMMUNITY_MANAGER_WITH_USER = - CommunityManager(id = IdGenerator.getAndIncrement(), personId = PERSON.id, staff = STAFF_WITH_USER) + CommunityManager(id = IdGenerator.getAndIncrement(), person = PERSON, staff = STAFF_WITH_USER) + + val MAIN_ADDRESS_TYPE = ReferenceData(id = IdGenerator.getAndIncrement(), code = "M", description = "Main") + val MAIN_ADDRESS = + Address( + id = IdGenerator.getAndIncrement(), + person = PERSON, + status = MAIN_ADDRESS_TYPE, + buildingName = "Building Name", + addressNumber = "123", + streetName = "Street Name", + district = "District", + townCity = "Town City", + county = "County", + postcode = "AA1 1AA", + noFixedAbode = false, + endDate = null, + softDeleted = false + ) } diff --git a/projects/prison-education-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt b/projects/prison-education-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt index ed59c45a4f..bdba17e13e 100644 --- a/projects/prison-education-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt +++ b/projects/prison-education-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/IntegrationTest.kt @@ -28,4 +28,19 @@ internal class IntegrationTest { .andExpect(jsonPath("lastName", equalTo("User"))) .andExpect(jsonPath("email", equalTo("test@example.com"))) } + + @Test + fun `get main address`() { + mockMvc + .perform(get("/probation-case/${PERSON.prisonerId}/main-address").withToken()) + .andExpect(status().is2xxSuccessful) + .andExpect(jsonPath("buildingName", equalTo("Building Name"))) + .andExpect(jsonPath("addressNumber", equalTo("123"))) + .andExpect(jsonPath("streetName", equalTo("Street Name"))) + .andExpect(jsonPath("district", equalTo("District"))) + .andExpect(jsonPath("town", equalTo("Town City"))) + .andExpect(jsonPath("county", equalTo("County"))) + .andExpect(jsonPath("postcode", equalTo("AA1 1AA"))) + .andExpect(jsonPath("noFixedAbode", equalTo(false))) + } } diff --git a/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/ApiController.kt b/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/ApiController.kt index 6a353b175f..837036d5fc 100644 --- a/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/ApiController.kt +++ b/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/ApiController.kt @@ -1,57 +1,66 @@ package uk.gov.justice.digital.hmpps.controller import io.swagger.v3.oas.annotations.Operation -import io.swagger.v3.oas.annotations.media.Content -import io.swagger.v3.oas.annotations.media.ExampleObject -import io.swagger.v3.oas.annotations.media.Schema -import io.swagger.v3.oas.annotations.responses.ApiResponse import org.springframework.ldap.core.LdapTemplate import org.springframework.security.access.prepost.PreAuthorize import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RestController -import uk.gov.justice.digital.hmpps.advice.ErrorResponse -import uk.gov.justice.digital.hmpps.entity.CommunityManager import uk.gov.justice.digital.hmpps.exception.NotFoundException import uk.gov.justice.digital.hmpps.ldap.findEmailByUsername +import uk.gov.justice.digital.hmpps.model.AddressResponse import uk.gov.justice.digital.hmpps.model.CommunityManagerResponse +import uk.gov.justice.digital.hmpps.repository.AddressRepository import uk.gov.justice.digital.hmpps.repository.CommunityManagerRepository import uk.gov.justice.digital.hmpps.repository.PersonRepository @RestController +@PreAuthorize("hasRole('PROBATION_API__PRISON_EDUCATION__CASE_DETAIL')") class ApiController( private val personRepository: PersonRepository, private val communityManagerRepository: CommunityManagerRepository, + private val addressRepository: AddressRepository, private val ldapTemplate: LdapTemplate ) { - @PreAuthorize("hasRole('PROBATION_API__PRISON_EDUCATION__CASE_DETAIL')") @GetMapping(value = ["/probation-case/{prisonerId}/community-manager"]) @Operation( summary = "Get the current active community manager for a probation case", description = """Accepts the prisoner identifier (NOMS number) and returns the currently active community manager of the probation case.

Requires `PROBATION_API__PRISON_EDUCATION__CASE_DETAIL`. - """, - responses = [ - ApiResponse(responseCode = "200", description = "OK"), - ApiResponse( - responseCode = "404", - description = "No probation case found with the given prisoner identifier. This could mean the Prison and Probation cases have not been linked yet.", - content = [Content( - schema = Schema(implementation = ErrorResponse::class), - examples = [ExampleObject("""{"status": 404, "message": "Person with prisonerId of A0000AA not found"}""")] - )] - ) - ] + """ ) fun getCommunityManager(@PathVariable prisonerId: String) = personRepository.findByPrisonerId(prisonerId) - ?.let { communityManagerRepository.findByPersonId(it.id).response } + ?.let { communityManagerRepository.findByPersonId(it.id).staff } + ?.let { + CommunityManagerResponse( + firstName = it.forename, + lastName = it.surname, + email = it.user?.username?.let { username -> ldapTemplate.findEmailByUsername(username) } + ) + } ?: throw NotFoundException("Person", "prisonerId", prisonerId) - val CommunityManager.response - get() = CommunityManagerResponse( - firstName = staff.forename, - lastName = staff.surname, - email = staff.user?.username?.let { ldapTemplate.findEmailByUsername(it) } - ) + @GetMapping(value = ["/probation-case/{prisonerId}/main-address"]) + @Operation( + summary = "Get the current main address for a probation case", + description = """Accepts the prisoner identifier (NOMS number) and returns the + current main address linked to the probation case. +

Requires `PROBATION_API__PRISON_EDUCATION__CASE_DETAIL`. + """ + ) + fun getMainAddress(@PathVariable prisonerId: String) = addressRepository.getMainAddressByPrisonerId(prisonerId) + ?.let { + AddressResponse( + buildingName = it.buildingName, + addressNumber = it.addressNumber, + streetName = it.streetName, + district = it.district, + town = it.townCity, + county = it.county, + postcode = it.postcode, + noFixedAbode = it.noFixedAbode + ) + } + ?: throw NotFoundException("Main address", "prisonerId", prisonerId) } diff --git a/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Address.kt b/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Address.kt new file mode 100644 index 0000000000..a0f77d3e39 --- /dev/null +++ b/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/Address.kt @@ -0,0 +1,34 @@ +package uk.gov.justice.digital.hmpps.entity + +import jakarta.persistence.* +import org.hibernate.annotations.Immutable +import org.hibernate.annotations.SQLRestriction +import org.hibernate.type.YesNoConverter +import java.time.LocalDate + +@Immutable +@Entity +@Table(name = "offender_address") +@SQLRestriction("soft_deleted = 0 and (end_date is null or end_date > current_date)") +class Address( + @Id + @Column(name = "offender_address_id") + val id: Long, + @ManyToOne + @JoinColumn(name = "offender_id") + val person: Person, + @ManyToOne + @JoinColumn(name = "address_status_id") + var status: ReferenceData, + val buildingName: String?, + val addressNumber: String?, + val streetName: String?, + val district: String?, + val townCity: String?, + val county: String?, + val postcode: String?, + @Convert(converter = YesNoConverter::class) + val noFixedAbode: Boolean? = false, + var endDate: LocalDate? = null, + val softDeleted: Boolean = false +) diff --git a/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/CommunityManager.kt b/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/CommunityManager.kt index 7d890c2020..aa5684d4c2 100644 --- a/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/CommunityManager.kt +++ b/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/CommunityManager.kt @@ -1,11 +1,6 @@ package uk.gov.justice.digital.hmpps.entity -import jakarta.persistence.Column -import jakarta.persistence.Entity -import jakarta.persistence.Id -import jakarta.persistence.JoinColumn -import jakarta.persistence.ManyToOne -import jakarta.persistence.Table +import jakarta.persistence.* import org.hibernate.annotations.Immutable import org.hibernate.annotations.SQLRestriction @@ -18,8 +13,9 @@ data class CommunityManager( @Column(name = "offender_manager_id") val id: Long, - @Column(name = "offender_id") - val personId: Long, + @ManyToOne + @JoinColumn(name = "offender_id") + val person: Person, @ManyToOne @JoinColumn(name = "allocation_staff_id") diff --git a/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/ReferenceData.kt b/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/ReferenceData.kt new file mode 100644 index 0000000000..8a9ec1593a --- /dev/null +++ b/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/ReferenceData.kt @@ -0,0 +1,22 @@ +package uk.gov.justice.digital.hmpps.entity + +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.Table +import org.hibernate.annotations.Immutable + +@Entity +@Immutable +@Table(name = "r_standard_reference_list") +class ReferenceData( + @Id + @Column(name = "standard_reference_list_id", nullable = false) + val id: Long, + + @Column(name = "code_value", length = 100, nullable = false) + val code: String, + + @Column(name = "code_description", length = 500, nullable = false) + val description: String +) diff --git a/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/model/AddressResponse.kt b/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/model/AddressResponse.kt new file mode 100644 index 0000000000..15e3f5b80f --- /dev/null +++ b/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/model/AddressResponse.kt @@ -0,0 +1,12 @@ +package uk.gov.justice.digital.hmpps.model + +data class AddressResponse( + val buildingName: String?, + val addressNumber: String?, + val streetName: String?, + val district: String?, + val town: String?, + val county: String?, + val postcode: String?, + val noFixedAbode: Boolean? +) \ No newline at end of file diff --git a/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/repository/AddressRepository.kt b/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/repository/AddressRepository.kt new file mode 100644 index 0000000000..2b7d0f7bbf --- /dev/null +++ b/projects/prison-education-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/repository/AddressRepository.kt @@ -0,0 +1,19 @@ +package uk.gov.justice.digital.hmpps.repository + +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import uk.gov.justice.digital.hmpps.entity.Address + +interface AddressRepository : JpaRepository { + @Query( + """ + select a from Address a + join fetch a.status + where a.person.prisonerId = :prisonerId + and a.softDeleted = false + and a.endDate is null + and a.status.code = 'M' + """ + ) + fun getMainAddressByPrisonerId(prisonerId: String): Address? +} \ No newline at end of file diff --git a/projects/prison-education-and-delius/src/main/resources/application.yml b/projects/prison-education-and-delius/src/main/resources/application.yml index 4750b1907c..433c0bc755 100644 --- a/projects/prison-education-and-delius/src/main/resources/application.yml +++ b/projects/prison-education-and-delius/src/main/resources/application.yml @@ -32,6 +32,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/prison-education-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/controller/ApiControllerTest.kt b/projects/prison-education-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/controller/ApiControllerTest.kt index 28f28db014..45c4b3bf02 100644 --- a/projects/prison-education-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/controller/ApiControllerTest.kt +++ b/projects/prison-education-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/controller/ApiControllerTest.kt @@ -15,8 +15,10 @@ import org.springframework.ldap.core.AttributesMapper import org.springframework.ldap.core.LdapTemplate import uk.gov.justice.digital.hmpps.data.generator.DataGenerator.COMMUNITY_MANAGER import uk.gov.justice.digital.hmpps.data.generator.DataGenerator.COMMUNITY_MANAGER_WITH_USER +import uk.gov.justice.digital.hmpps.data.generator.DataGenerator.MAIN_ADDRESS import uk.gov.justice.digital.hmpps.data.generator.DataGenerator.PERSON import uk.gov.justice.digital.hmpps.exception.NotFoundException +import uk.gov.justice.digital.hmpps.repository.AddressRepository import uk.gov.justice.digital.hmpps.repository.CommunityManagerRepository import uk.gov.justice.digital.hmpps.repository.PersonRepository @@ -28,6 +30,9 @@ class ApiControllerTest { @Mock private lateinit var communityManagerRepository: CommunityManagerRepository + @Mock + private lateinit var addressRepository: AddressRepository + @Mock private lateinit var ldapTemplate: LdapTemplate @@ -43,6 +48,15 @@ class ApiControllerTest { } } + @Test + fun `missing person is thrown for address`() { + assertThrows { + apiController.getMainAddress(PERSON.prisonerId) + }.run { + assertThat(message, equalTo("Main address with prisonerId of A0000AA not found")) + } + } + @Test fun `unlinked user account results in null email`() { whenever(personRepository.findByPrisonerId(PERSON.prisonerId)).thenReturn(PERSON) @@ -67,4 +81,20 @@ class ApiControllerTest { assertThat(email, equalTo("test@example.com")) } } + + @Test + fun `main address is returned`() { + whenever(addressRepository.getMainAddressByPrisonerId(PERSON.prisonerId)).thenReturn(MAIN_ADDRESS) + + apiController.getMainAddress(PERSON.prisonerId).run { + assertThat(buildingName, equalTo("Building Name")) + assertThat(addressNumber, equalTo("123")) + assertThat(streetName, equalTo("Street Name")) + assertThat(district, equalTo("District")) + assertThat(town, equalTo("Town City")) + assertThat(county, equalTo("County")) + assertThat(postcode, equalTo("AA1 1AA")) + assertThat(noFixedAbode, equalTo(false)) + } + } } diff --git a/projects/prison-identifier-and-delius/README.md b/projects/prison-identifier-and-delius/README.md index 41a98845d9..bee0f78178 100644 --- a/projects/prison-identifier-and-delius/README.md +++ b/projects/prison-identifier-and-delius/README.md @@ -1,5 +1,8 @@ # Prison Identifier and Delius +Service that supports matching NOMIS person records to Delius person records using the basic personal details and the +recorded sentence dates. + ## Business Need HMPPS has a number of systems each holding information about a person's interaction with different aspects of the justice system. These systems have been set up and managed over a long period of time resulting in different identifiers being used for a person in each. In order to integrate these independent systems we must match the person records using the information held in each. To achieve this for NOMIS (NOMS Number) and Delius (CRN) we query the two systems and determine that likely matches based on the data. Once we have a likely match we can link the records by adding the NOMS Number to the person record in the Delius database. When this link is in place the two systems can be integrated in other ways to support case management as the person moves through different stages of HMPPS supervision. diff --git a/projects/prison-identifier-and-delius/deploy/values.yaml b/projects/prison-identifier-and-delius/deploy/values.yaml index 1174dc7215..6d9f7e516d 100644 --- a/projects/prison-identifier-and-delius/deploy/values.yaml +++ b/projects/prison-identifier-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: prison-identifier-and-delius serviceAccountName: prison-identifier-and-delius diff --git a/projects/prison-identifier-and-delius/src/main/resources/application.yml b/projects/prison-identifier-and-delius/src/main/resources/application.yml index 6161009479..7b21f4d530 100644 --- a/projects/prison-identifier-and-delius/src/main/resources/application.yml +++ b/projects/prison-identifier-and-delius/src/main/resources/application.yml @@ -38,6 +38,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/projects/prisoner-profile-and-delius/deploy/values.yaml b/projects/prisoner-profile-and-delius/deploy/values.yaml index 496e96356c..726db6e023 100644 --- a/projects/prisoner-profile-and-delius/deploy/values.yaml +++ b/projects/prisoner-profile-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: prisoner-profile-and-delius image: diff --git a/projects/prisoner-profile-and-delius/src/main/resources/application.yml b/projects/prisoner-profile-and-delius/src/main/resources/application.yml index e0a96cea66..08be4caf60 100644 --- a/projects/prisoner-profile-and-delius/src/main/resources/application.yml +++ b/projects/prisoner-profile-and-delius/src/main/resources/application.yml @@ -34,6 +34,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/probation-search-and-delius/deploy/values.yaml b/projects/probation-search-and-delius/deploy/values.yaml index 151d27f80d..a9ad4660c0 100644 --- a/projects/probation-search-and-delius/deploy/values.yaml +++ b/projects/probation-search-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: probation-search-and-delius image: diff --git a/projects/probation-search-and-delius/src/main/resources/application.yml b/projects/probation-search-and-delius/src/main/resources/application.yml index e26caf7c4e..5b00887651 100644 --- a/projects/probation-search-and-delius/src/main/resources/application.yml +++ b/projects/probation-search-and-delius/src/main/resources/application.yml @@ -28,6 +28,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/redrive-dead-letter-queues/container/Dockerfile b/projects/redrive-dead-letter-queues/container/Dockerfile index 2b0ca85982..62c7acd13c 100644 --- a/projects/redrive-dead-letter-queues/container/Dockerfile +++ b/projects/redrive-dead-letter-queues/container/Dockerfile @@ -1,4 +1,4 @@ -FROM public.ecr.aws/aws-cli/aws-cli:2.15.43 +FROM public.ecr.aws/aws-cli/aws-cli:2.15.62 USER root SHELL ["/bin/bash", "-o", "pipefail", "-c"] diff --git a/projects/refer-and-monitor-and-delius/README.md b/projects/refer-and-monitor-and-delius/README.md index 21f9910751..80e5793c7c 100644 --- a/projects/refer-and-monitor-and-delius/README.md +++ b/projects/refer-and-monitor-and-delius/README.md @@ -1,5 +1,8 @@ # Refer and Monitor and Delius +Service that supports creating and managing the referral of a person on probation to a CRS intervention, by providing +Delius information and listening to domain events to create Contacts and NSIs in Delius. + ## Business Need _Refer and Monitor an Intervention_ has a tightly coupled relationship with _Delius_ due to activity managed in both systems being important for workflows in the other. _Refer and Monitor an Intervention_ depends on information managed in _Delius_ for it's primary function of creating and managing CRS referrals. There is also a requirement to write information back to _Delius_ when various activities are recorded in _Refer and Monitor an Intervention_. Where possible the interaction between the two services is managed asynchronously via domain events but there are workflows in _Refer and Monitor an Intervention_ that have runtime dependency on successful creation of entities in _Delius_. In these cases the cross-service interaction is via synchronous API calls. diff --git a/projects/refer-and-monitor-and-delius/deploy/values.yaml b/projects/refer-and-monitor-and-delius/deploy/values.yaml index dac3d4b1d4..ac06b2fd2b 100644 --- a/projects/refer-and-monitor-and-delius/deploy/values.yaml +++ b/projects/refer-and-monitor-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: refer-and-monitor-and-delius serviceAccountName: refer-and-monitor-and-delius diff --git a/projects/refer-and-monitor-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/ContractTypeNsiType.kt b/projects/refer-and-monitor-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/ContractTypeNsiType.kt index 81ed741fba..6eefbada88 100644 --- a/projects/refer-and-monitor-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/ContractTypeNsiType.kt +++ b/projects/refer-and-monitor-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/ContractTypeNsiType.kt @@ -13,6 +13,7 @@ object ContractTypeNsiType { "FBD-BU" to "CRS08", "FBD-EM" to "CRS08", "FBD-M" to "CRS08", + "FBD-O" to "CRS08", "FBD-R" to "CRS08", "FBD-WM" to "CRS08", "FBD-L" to "CRS08", diff --git a/projects/refer-and-monitor-and-delius/src/main/resources/application.yml b/projects/refer-and-monitor-and-delius/src/main/resources/application.yml index 9fbad28218..360147c891 100644 --- a/projects/refer-and-monitor-and-delius/src/main/resources/application.yml +++ b/projects/refer-and-monitor-and-delius/src/main/resources/application.yml @@ -42,6 +42,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/projects/resettlement-passport-and-delius/deploy/values.yaml b/projects/resettlement-passport-and-delius/deploy/values.yaml index 919da8c095..b60c23ce10 100644 --- a/projects/resettlement-passport-and-delius/deploy/values.yaml +++ b/projects/resettlement-passport-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: resettlement-passport-and-delius image: diff --git a/projects/resettlement-passport-and-delius/src/main/resources/application.yml b/projects/resettlement-passport-and-delius/src/main/resources/application.yml index 58016805af..e3080892e3 100644 --- a/projects/resettlement-passport-and-delius/src/main/resources/application.yml +++ b/projects/resettlement-passport-and-delius/src/main/resources/application.yml @@ -32,6 +32,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/risk-assessment-scores-to-delius/deploy/values.yaml b/projects/risk-assessment-scores-to-delius/deploy/values.yaml index 0d76339d3f..8837612c65 100644 --- a/projects/risk-assessment-scores-to-delius/deploy/values.yaml +++ b/projects/risk-assessment-scores-to-delius/deploy/values.yaml @@ -2,6 +2,7 @@ # Values here are the same across all environments # An additional set of default values can be found in templates/helm-defaults.yml, which is the same across all projects generic-service: + productId: HMPPS518 nameOverride: risk-assessment-scores-to-delius serviceAccountName: risk-assessment-scores-to-delius diff --git a/projects/risk-assessment-scores-to-delius/src/main/resources/application.yml b/projects/risk-assessment-scores-to-delius/src/main/resources/application.yml index 66978d9868..8a6d555bc5 100644 --- a/projects/risk-assessment-scores-to-delius/src/main/resources/application.yml +++ b/projects/risk-assessment-scores-to-delius/src/main/resources/application.yml @@ -26,6 +26,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/sentence-plan-and-delius/deploy/values.yaml b/projects/sentence-plan-and-delius/deploy/values.yaml index 2efee28ec8..54360f0afd 100644 --- a/projects/sentence-plan-and-delius/deploy/values.yaml +++ b/projects/sentence-plan-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: sentence-plan-and-delius image: diff --git a/projects/sentence-plan-and-delius/src/main/resources/application.yml b/projects/sentence-plan-and-delius/src/main/resources/application.yml index b8f97b42b4..d03a7ee3af 100644 --- a/projects/sentence-plan-and-delius/src/main/resources/application.yml +++ b/projects/sentence-plan-and-delius/src/main/resources/application.yml @@ -28,6 +28,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/sentence-plan-and-oasys/deploy/values.yaml b/projects/sentence-plan-and-oasys/deploy/values.yaml index 3248a9c9b3..04f80dfbe1 100644 --- a/projects/sentence-plan-and-oasys/deploy/values.yaml +++ b/projects/sentence-plan-and-oasys/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: sentence-plan-and-oasys image: diff --git a/projects/sentence-plan-and-oasys/src/main/resources/application.yml b/projects/sentence-plan-and-oasys/src/main/resources/application.yml index e805f2d56b..970e80193e 100644 --- a/projects/sentence-plan-and-oasys/src/main/resources/application.yml +++ b/projects/sentence-plan-and-oasys/src/main/resources/application.yml @@ -13,6 +13,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/projects/soc-and-delius/deploy/values.yaml b/projects/soc-and-delius/deploy/values.yaml index 6e07956fdd..65c9b03100 100644 --- a/projects/soc-and-delius/deploy/values.yaml +++ b/projects/soc-and-delius/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: soc-and-delius image: diff --git a/projects/soc-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ConvictionEventGenerator.kt b/projects/soc-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ConvictionEventGenerator.kt index d05bb983ee..081170b17d 100644 --- a/projects/soc-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ConvictionEventGenerator.kt +++ b/projects/soc-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ConvictionEventGenerator.kt @@ -1,12 +1,6 @@ package uk.gov.justice.digital.hmpps.data.generator -import uk.gov.justice.digital.hmpps.entity.AdditionalOffence -import uk.gov.justice.digital.hmpps.entity.ConvictionEventEntity -import uk.gov.justice.digital.hmpps.entity.ConvictionEventPerson -import uk.gov.justice.digital.hmpps.entity.Disposal -import uk.gov.justice.digital.hmpps.entity.DisposalType -import uk.gov.justice.digital.hmpps.entity.MainOffence -import uk.gov.justice.digital.hmpps.entity.Offence +import uk.gov.justice.digital.hmpps.entity.* import java.time.LocalDate object ConvictionEventGenerator { @@ -30,11 +24,13 @@ object ConvictionEventGenerator { val DEFAULT_EVENT = ConvictionEventEntity( IdGenerator.getAndIncrement(), LocalDate.now().minusDays(1), + LocalDate.now().minusDays(2), PERSON ) val INACTIVE_EVENT = ConvictionEventEntity( IdGenerator.getAndIncrement(), LocalDate.now(), + LocalDate.now().minusDays(1), PERSON, active = false ) @@ -67,6 +63,7 @@ object ConvictionEventGenerator { val EVENT_2 = ConvictionEventEntity( IdGenerator.getAndIncrement(), LocalDate.now(), + LocalDate.now(), PERSON_2 ) val MAIN_OFFENCE_2 = MainOffence( diff --git a/projects/soc-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/ConvictionsIntegrationTest.kt b/projects/soc-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/ConvictionsIntegrationTest.kt index 9206d93db9..e049c612f8 100644 --- a/projects/soc-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/ConvictionsIntegrationTest.kt +++ b/projects/soc-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/ConvictionsIntegrationTest.kt @@ -61,6 +61,7 @@ internal class ConvictionsIntegrationTest { Conviction( ConvictionEventGenerator.DEFAULT_EVENT.id, ConvictionEventGenerator.DEFAULT_EVENT.convictionDate, + ConvictionEventGenerator.DEFAULT_EVENT.referralDate, ConvictionEventGenerator.DISPOSAL_TYPE.description, listOf( Offence( @@ -100,6 +101,7 @@ internal class ConvictionsIntegrationTest { val inactiveConviction = Conviction( ConvictionEventGenerator.INACTIVE_EVENT.id, ConvictionEventGenerator.INACTIVE_EVENT.convictionDate, + ConvictionEventGenerator.INACTIVE_EVENT.referralDate, "unknown", listOf(), null diff --git a/projects/soc-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/CourtAppearancesIntegrationTest.kt b/projects/soc-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/CourtAppearancesIntegrationTest.kt index e557f41c69..f2509ca3c2 100644 --- a/projects/soc-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/CourtAppearancesIntegrationTest.kt +++ b/projects/soc-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/CourtAppearancesIntegrationTest.kt @@ -24,7 +24,7 @@ internal class CourtAppearancesIntegrationTest { @Test fun `API call retuns a success response`() { val crn = CourtAppearanceGenerator.DEFAULT_PERSON.crn - val detailResponse = mockMvc + mockMvc .perform(get("/court-appearances/$crn").withToken()) .andExpect(status().is2xxSuccessful) .andExpectJson(getCourtAppearances()) diff --git a/projects/soc-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/ConvictionEventEntity.kt b/projects/soc-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/ConvictionEventEntity.kt index 3a37e3c9c9..fe319785bd 100644 --- a/projects/soc-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/ConvictionEventEntity.kt +++ b/projects/soc-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/entity/ConvictionEventEntity.kt @@ -1,13 +1,6 @@ package uk.gov.justice.digital.hmpps.entity -import jakarta.persistence.Column -import jakarta.persistence.Entity -import jakarta.persistence.Id -import jakarta.persistence.JoinColumn -import jakarta.persistence.ManyToOne -import jakarta.persistence.OneToMany -import jakarta.persistence.OneToOne -import jakarta.persistence.Table +import jakarta.persistence.* import org.hibernate.annotations.Immutable import org.hibernate.annotations.SQLRestriction import org.springframework.data.jpa.repository.EntityGraph @@ -26,6 +19,8 @@ class ConvictionEventEntity( val convictionDate: LocalDate?, + val referralDate: LocalDate, + @ManyToOne @JoinColumn(name = "offender_id", nullable = false) val convictionEventPerson: ConvictionEventPerson, diff --git a/projects/soc-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/model/Conviction.kt b/projects/soc-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/model/Conviction.kt index 4e0f1f74c4..0bb28d5b00 100644 --- a/projects/soc-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/model/Conviction.kt +++ b/projects/soc-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/model/Conviction.kt @@ -5,6 +5,7 @@ import java.time.LocalDate data class Conviction( val convictionId: Long, val convictionDate: LocalDate?, + val referralDate: LocalDate, val outcome: String, val offences: List, val sentence: Sentence? diff --git a/projects/soc-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/ConvictionService.kt b/projects/soc-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/ConvictionService.kt index 6ca57f4165..ef1d4d4006 100644 --- a/projects/soc-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/ConvictionService.kt +++ b/projects/soc-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/ConvictionService.kt @@ -2,17 +2,11 @@ package uk.gov.justice.digital.hmpps.service import org.springframework.stereotype.Service import uk.gov.justice.digital.hmpps.controller.IdentifierType -import uk.gov.justice.digital.hmpps.entity.ConvictionEventRepository -import uk.gov.justice.digital.hmpps.entity.CustodyRepository -import uk.gov.justice.digital.hmpps.entity.Disposal +import uk.gov.justice.digital.hmpps.entity.* import uk.gov.justice.digital.hmpps.entity.KeyDate -import uk.gov.justice.digital.hmpps.entity.ReferenceData -import uk.gov.justice.digital.hmpps.model.Conviction -import uk.gov.justice.digital.hmpps.model.ConvictionsContainer +import uk.gov.justice.digital.hmpps.model.* import uk.gov.justice.digital.hmpps.model.Custody -import uk.gov.justice.digital.hmpps.model.CustodyStatus import uk.gov.justice.digital.hmpps.model.Offence -import uk.gov.justice.digital.hmpps.model.Sentence @Service class ConvictionService( @@ -65,6 +59,7 @@ class ConvictionService( Conviction( convictionEventEntity.id, convictionEventEntity.convictionDate, + convictionEventEntity.referralDate, convictionEventEntity.disposal?.type?.description ?: "unknown", offences, convictionEventEntity.disposal?.asModel(custody) diff --git a/projects/soc-and-delius/src/main/resources/application.yml b/projects/soc-and-delius/src/main/resources/application.yml index 834e55cddf..6d6d42495c 100644 --- a/projects/soc-and-delius/src/main/resources/application.yml +++ b/projects/soc-and-delius/src/main/resources/application.yml @@ -28,6 +28,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/projects/tier-to-delius/deploy/values.yaml b/projects/tier-to-delius/deploy/values.yaml index 56791df56f..456fa60aa0 100644 --- a/projects/tier-to-delius/deploy/values.yaml +++ b/projects/tier-to-delius/deploy/values.yaml @@ -2,6 +2,7 @@ # Values here are the same across all environments # An additional set of default values can be found in templates/helm-defaults.yml, which is the same across all projects generic-service: + productId: HMPPS518 nameOverride: tier-to-delius serviceAccountName: tier-to-delius diff --git a/projects/tier-to-delius/src/main/resources/application.yml b/projects/tier-to-delius/src/main/resources/application.yml index 733f8add26..e3098684c9 100644 --- a/projects/tier-to-delius/src/main/resources/application.yml +++ b/projects/tier-to-delius/src/main/resources/application.yml @@ -38,6 +38,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + crn-streaming.timeout: 300000 --- diff --git a/projects/unpaid-work-and-delius/build.gradle.kts b/projects/unpaid-work-and-delius/build.gradle.kts index 2a17034144..b3460dbea5 100644 --- a/projects/unpaid-work-and-delius/build.gradle.kts +++ b/projects/unpaid-work-and-delius/build.gradle.kts @@ -19,8 +19,6 @@ dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") implementation(libs.springdoc) - implementation(libs.mapstruct) - kapt(libs.mapstructprocessor) dev(project(":libs:dev-tools")) dev("com.h2database:h2") diff --git a/projects/unpaid-work-and-delius/deploy/values.yaml b/projects/unpaid-work-and-delius/deploy/values.yaml index ef95527806..1ac4d7bf82 100644 --- a/projects/unpaid-work-and-delius/deploy/values.yaml +++ b/projects/unpaid-work-and-delius/deploy/values.yaml @@ -2,6 +2,7 @@ # Values here are the same across all environments # An additional set of default values can be found in templates/helm-defaults.yml, which is the same across all projects generic-service: + productId: HMPPS518 nameOverride: unpaid-work-and-delius serviceAccountName: unpaid-work-and-delius diff --git a/projects/unpaid-work-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/casedetails/CaseDetailsService.kt b/projects/unpaid-work-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/casedetails/CaseDetailsService.kt index 0f7910adf8..ed855417d3 100644 --- a/projects/unpaid-work-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/casedetails/CaseDetailsService.kt +++ b/projects/unpaid-work-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/casedetails/CaseDetailsService.kt @@ -5,17 +5,120 @@ import uk.gov.justice.digital.hmpps.controller.casedetails.entity.CaseRepository import uk.gov.justice.digital.hmpps.controller.casedetails.entity.EventRepository import uk.gov.justice.digital.hmpps.controller.casedetails.entity.getCase import uk.gov.justice.digital.hmpps.controller.casedetails.entity.getEvent -import uk.gov.justice.digital.hmpps.controller.casedetails.model.CaseDetails +import uk.gov.justice.digital.hmpps.controller.casedetails.model.* +import uk.gov.justice.digital.hmpps.integrations.common.model.* @Service class CaseDetailsService( val caseRepository: CaseRepository, - val eventRepository: EventRepository, - val caseMapper: CaseMapper + val eventRepository: EventRepository ) { fun getCaseDetails(crn: String, eventId: Long): CaseDetails { val case = caseRepository.getCase(crn) val event = eventRepository.getEvent(eventId) - return caseMapper.withAdditionalMappings(case, event) + return CaseDetails( + crn = case.crn, + name = Name( + forename = case.forename, + middleName = case.secondName, + surname = case.surname + ), + dateOfBirth = case.dateOfBirth, + gender = case.gender?.description, + genderIdentity = case.genderIdentity?.description, + croNumber = case.croNumber, + pncNumber = case.pncNumber, + aliases = case.aliases.map { Alias(it.name(), it.dateOfBirth) }, + emailAddress = case.emailAddress, + phoneNumbers = listOfNotNull( + case.mobileNumber?.let { PhoneNumber("MOBILE", it) }, + case.telephoneNumber?.let { PhoneNumber("TELEPHONE", it) } + ), + mainAddress = case.addresses.firstOrNull()?.let { + Address(it.buildingName, it.addressNumber, it.streetName, it.district, it.town, it.county, it.postcode) + }, + ethnicity = case.ethnicity?.description, + disabilities = case.disabilities.map { + Disability( + type = Type(it.type.code, it.type.description), + condition = it.condition?.let { c -> Type(c.code, c.description) }, + notes = it.notes + ) + }, + provisions = case.provisions.map { + Provision( + type = Type(it.type.code, it.type.description), + category = it.category?.let { c -> Type(c.code, c.description) }, + notes = it.notes + ) + }, + language = case.primaryLanguage?.description?.let { + Language( + requiresInterpreter = case.requiresInterpreter ?: false, + primaryLanguage = it + ) + }, + personalCircumstances = case.personalCircumstances.map { + PersonalCircumstance( + type = Type(it.type.code, it.type.description), + subType = it.subType?.let { t -> Type(t.code, t.description) }, + notes = it.notes, + evidenced = it.evidenced ?: false + ) + }, + personalContacts = case.personalContacts.map { + PersonalContact( + relationship = it.relationship, + relationshipType = Type(it.relationshipType.code, it.relationshipType.description), + name = it.name(), + mobileNumber = it.mobileNumber, + telephoneNumber = it.address?.telephoneNumber, + address = it.address?.let { address -> + Address( + buildingName = address.buildingName, + addressNumber = address.addressNumber, + streetName = address.streetName, + district = address.district, + town = address.town, + county = address.county, + postcode = address.postcode + ) + } + ) + }, + mappaRegistration = case.registrations.filter { it.type.code == "MAPPA" }.maxByOrNull { it.startDate } + ?.let { + MappaRegistration( + startDate = it.startDate, + level = Type(it.level.code, it.level.description), + category = Type(it.category.code, it.category.description) + ) + }, + registerFlags = case.registrations.map { + RegisterFlag( + code = it.type.code, + description = it.type.description, + riskColour = it.type.riskColour + ) + }, + sentence = if (event.mainOffence != null && event.disposal != null) { + Sentence( + startDate = event.disposal.disposalDate, + mainOffence = MainOffence( + Type( + event.mainOffence.offence.mainCategoryCode, + event.mainOffence.offence.mainCategoryDescription + ), + Type( + event.mainOffence.offence.subCategoryCode, + event.mainOffence.offence.subCategoryDescription + ) + ) + ) + } else { + null + } + + ) } } diff --git a/projects/unpaid-work-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/casedetails/CaseMapper.kt b/projects/unpaid-work-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/casedetails/CaseMapper.kt deleted file mode 100644 index 6aabea4608..0000000000 --- a/projects/unpaid-work-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/casedetails/CaseMapper.kt +++ /dev/null @@ -1,163 +0,0 @@ -package uk.gov.justice.digital.hmpps.controller.casedetails - -import org.mapstruct.Mapper -import org.mapstruct.Mapping -import uk.gov.justice.digital.hmpps.controller.casedetails.entity.CaseAddress -import uk.gov.justice.digital.hmpps.controller.casedetails.entity.CaseEntity -import uk.gov.justice.digital.hmpps.controller.casedetails.entity.CasePersonalCircumstanceEntity -import uk.gov.justice.digital.hmpps.controller.casedetails.entity.CasePersonalContactEntity -import uk.gov.justice.digital.hmpps.controller.casedetails.entity.DisabilityEntity -import uk.gov.justice.digital.hmpps.controller.casedetails.entity.Event -import uk.gov.justice.digital.hmpps.controller.casedetails.model.Alias -import uk.gov.justice.digital.hmpps.controller.casedetails.model.CaseDetails -import uk.gov.justice.digital.hmpps.controller.casedetails.model.Disability -import uk.gov.justice.digital.hmpps.controller.casedetails.model.Language -import uk.gov.justice.digital.hmpps.controller.casedetails.model.MainOffence -import uk.gov.justice.digital.hmpps.controller.casedetails.model.MappaRegistration -import uk.gov.justice.digital.hmpps.controller.casedetails.model.PhoneNumber -import uk.gov.justice.digital.hmpps.controller.casedetails.model.Provision -import uk.gov.justice.digital.hmpps.controller.casedetails.model.RegisterFlag -import uk.gov.justice.digital.hmpps.controller.casedetails.model.Sentence -import uk.gov.justice.digital.hmpps.controller.casedetails.model.name -import uk.gov.justice.digital.hmpps.integrations.common.mapper.AddressMapper -import uk.gov.justice.digital.hmpps.integrations.common.model.Address -import uk.gov.justice.digital.hmpps.integrations.common.model.PersonalCircumstance -import uk.gov.justice.digital.hmpps.integrations.common.model.PersonalContact -import uk.gov.justice.digital.hmpps.integrations.common.model.Type - -@Mapper( - componentModel = "spring", - uses = [ - CasePersonalCircumstanceMapper::class, - CasePersonalContactMapper::class, - AddressMapper::class, - CaseAddressMapper::class, - DisabilityMapper::class - ] -) -interface CaseMapper { - @Mapping(source = "surname", target = "name.surname") - @Mapping(source = "forename", target = "name.forename") - @Mapping(source = "secondName", target = "name.middleName") - @Mapping(source = "gender.description", target = "gender") - @Mapping(source = "genderIdentity.description", target = "genderIdentity") - @Mapping(source = "ethnicity.description", target = "ethnicity") - @Mapping(target = "aliases", ignore = true) - @Mapping(target = "phoneNumbers", ignore = true) - @Mapping(target = "registerFlags", ignore = true) - @Mapping(target = "language", ignore = true) - @Mapping(target = "mappaRegistration", ignore = true) - @Mapping(target = "sentence", ignore = true) - @Mapping(target = "mainAddress", ignore = true) - fun convertToModel(case: CaseEntity): CaseDetails -} - -fun CaseMapper.withAdditionalMappings(case: CaseEntity, event: Event): CaseDetails { - fun String.language(requiresInterpreter: Boolean) = Language(requiresInterpreter, this) - - val phoneNumbers = listOfNotNull( - case.mobileNumber?.let { PhoneNumber("MOBILE", it) }, - case.telephoneNumber?.let { PhoneNumber("TELEPHONE", it) } - ) - - val aliases = case.aliases.map { - Alias(it.name(), it.dateOfBirth) - } - - val sentence = if (event.mainOffence != null && event.disposal != null) { - Sentence( - event.disposal.disposalDate, - MainOffence( - Type(event.mainOffence.offence.mainCategoryCode, event.mainOffence.offence.mainCategoryDescription), - Type(event.mainOffence.offence.subCategoryCode, event.mainOffence.offence.subCategoryDescription) - ) - ) - } else { - null - } - - val model = convertToModel(case) - - val disabilities = case.disabilities.map { d -> - Disability( - Type(d.type.code, d.type.description), - d.condition?.let { con -> Type(con.code, con.description) }, - d.notes - ) - } - - val provisions = case.provisions.map { p -> - Provision( - Type(p.type.code, p.type.description), - p.category?.let { cat -> Type(cat.code, cat.description) }, - p.notes - ) - } - - val mainAddress = case.addresses.firstOrNull()?.let { - Address(it.buildingName, it.addressNumber, it.streetName, it.district, it.town, it.county, it.postcode) - } - - return model.copy( - aliases = aliases, - phoneNumbers = phoneNumbers, - mappaRegistration = populateMappaRegistration(case), - registerFlags = populateRegisterFlags(case), - language = case.primaryLanguage?.description?.language(case.requiresInterpreter ?: false), - sentence = sentence, - disabilities = disabilities, - provisions = provisions, - mainAddress = mainAddress - ) -} - -fun populateRegisterFlags(case: CaseEntity): List { - return case.registrations.map { - RegisterFlag( - it.type.code, - it.type.description, - it.type.riskColour - ) - } -} - -fun populateMappaRegistration(case: CaseEntity): MappaRegistration? { - val mappaRegistrations = - case.registrations.sortedByDescending { it.startDate }.stream().filter { - it.type.code == "MAPPA" - } - - return mappaRegistrations.findFirst().map { - MappaRegistration( - it.startDate, - Type(it.level.code, it.level.description), - Type(it.category.code, it.category.description) - ) - }.orElse(null) -} - -@Mapper(componentModel = "spring") -interface CasePersonalCircumstanceMapper { - @Mapping(source = "evidenced", target = "evidenced", defaultValue = "false") - fun convertToModel(personalCircumstanceEntity: CasePersonalCircumstanceEntity): PersonalCircumstance -} - -@Mapper(componentModel = "spring") -interface CaseAddressMapper { - fun convertToModel(caseAddress: CaseAddress): Address -} - -@Mapper(componentModel = "spring") -interface CasePersonalContactMapper { - - @Mapping(source = "surname", target = "name.surname") - @Mapping(source = "forename", target = "name.forename") - @Mapping(source = "middleName", target = "name.middleName") - @Mapping(source = "address.telephoneNumber", target = "telephoneNumber") - fun convertToModel(personalContactEntity: CasePersonalContactEntity): PersonalContact -} - -@Mapper(componentModel = "spring") -interface DisabilityMapper { - fun convertToModel(disabilityEntity: DisabilityEntity): Disability -} diff --git a/projects/unpaid-work-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/personaldetails/PersonMapper.kt b/projects/unpaid-work-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/personaldetails/PersonMapper.kt deleted file mode 100644 index 0a1276d934..0000000000 --- a/projects/unpaid-work-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/personaldetails/PersonMapper.kt +++ /dev/null @@ -1,34 +0,0 @@ -package uk.gov.justice.digital.hmpps.controller.personaldetails - -import org.mapstruct.Mapper -import org.mapstruct.Mapping -import uk.gov.justice.digital.hmpps.controller.personaldetails.entity.Person -import uk.gov.justice.digital.hmpps.controller.personaldetails.entity.PersonalCircumstanceEntity -import uk.gov.justice.digital.hmpps.controller.personaldetails.entity.PersonalContactEntity -import uk.gov.justice.digital.hmpps.controller.personaldetails.model.PersonalDetails -import uk.gov.justice.digital.hmpps.integrations.common.mapper.AddressMapper -import uk.gov.justice.digital.hmpps.integrations.common.model.PersonalCircumstance -import uk.gov.justice.digital.hmpps.integrations.common.model.PersonalContact - -@Mapper( - componentModel = "spring", - uses = [PersonalCircumstanceMapper::class, PersonalContactMapper::class, AddressMapper::class] -) -interface PersonMapper { - fun convertToModel(person: Person): PersonalDetails -} - -@Mapper(componentModel = "spring") -interface PersonalCircumstanceMapper { - fun convertToModel(personalCircumstanceEntity: PersonalCircumstanceEntity): PersonalCircumstance -} - -@Mapper(componentModel = "spring") -interface PersonalContactMapper { - - @Mapping(source = "surname", target = "name.surname") - @Mapping(source = "forename", target = "name.forename") - @Mapping(source = "middleName", target = "name.middleName") - @Mapping(source = "address.telephoneNumber", target = "telephoneNumber") - fun convertToModel(personalContactEntity: PersonalContactEntity): PersonalContact -} diff --git a/projects/unpaid-work-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/personaldetails/PersonalDetailsService.kt b/projects/unpaid-work-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/personaldetails/PersonalDetailsService.kt index e7c01ba2a6..7527740895 100644 --- a/projects/unpaid-work-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/personaldetails/PersonalDetailsService.kt +++ b/projects/unpaid-work-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/controller/personaldetails/PersonalDetailsService.kt @@ -4,11 +4,45 @@ import org.springframework.stereotype.Service import uk.gov.justice.digital.hmpps.controller.personaldetails.entity.PersonRepository import uk.gov.justice.digital.hmpps.controller.personaldetails.entity.getPerson import uk.gov.justice.digital.hmpps.controller.personaldetails.model.PersonalDetails +import uk.gov.justice.digital.hmpps.controller.personaldetails.model.name +import uk.gov.justice.digital.hmpps.integrations.common.model.Address +import uk.gov.justice.digital.hmpps.integrations.common.model.PersonalCircumstance +import uk.gov.justice.digital.hmpps.integrations.common.model.PersonalContact +import uk.gov.justice.digital.hmpps.integrations.common.model.Type @Service -class PersonalDetailsService(val personRepository: PersonRepository, val personMapper: PersonMapper) { - fun getPersonalDetails(crn: String): PersonalDetails { - val person = personRepository.getPerson(crn) - return personMapper.convertToModel(person) +class PersonalDetailsService(val personRepository: PersonRepository) { + fun getPersonalDetails(crn: String) = with(personRepository.getPerson(crn)) { + PersonalDetails( + crn = crn, + personalCircumstances = personalCircumstances.map { + PersonalCircumstance( + type = Type(it.type.code, it.type.description), + subType = it.subType?.let { t -> Type(t.code, t.description) }, + notes = it.notes, + evidenced = it.evidenced ?: false + ) + }, + personalContacts = personalContacts.map { + PersonalContact( + relationship = it.relationship, + relationshipType = Type(it.relationshipType.code, it.relationshipType.description), + name = it.name(), + telephoneNumber = it.address?.telephoneNumber, + mobileNumber = it.mobileNumber, + address = it.address?.let { address -> + Address( + buildingName = address.buildingName, + addressNumber = address.addressNumber, + streetName = address.streetName, + district = address.district, + town = address.town, + county = address.county, + postcode = address.postcode + ) + } + ) + } + ) } } diff --git a/projects/unpaid-work-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/common/mapper/AddressMapper.kt b/projects/unpaid-work-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/common/mapper/AddressMapper.kt deleted file mode 100644 index b6a21e0427..0000000000 --- a/projects/unpaid-work-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/common/mapper/AddressMapper.kt +++ /dev/null @@ -1,10 +0,0 @@ -package uk.gov.justice.digital.hmpps.integrations.common.mapper - -import org.mapstruct.Mapper -import uk.gov.justice.digital.hmpps.integrations.common.entity.AddressEntity -import uk.gov.justice.digital.hmpps.integrations.common.model.Address - -@Mapper(componentModel = "spring") -interface AddressMapper { - fun convertToModel(addressEntity: AddressEntity): Address -} diff --git a/projects/unpaid-work-and-delius/src/main/resources/application.yml b/projects/unpaid-work-and-delius/src/main/resources/application.yml index ca786ff7e9..4436e01b9c 100644 --- a/projects/unpaid-work-and-delius/src/main/resources/application.yml +++ b/projects/unpaid-work-and-delius/src/main/resources/application.yml @@ -38,6 +38,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/projects/workforce-allocations-to-delius/deploy/templates/initial-allocations-report.yaml b/projects/workforce-allocations-to-delius/deploy/templates/initial-allocations-report.yaml index fb7ef82762..52ef085c75 100644 --- a/projects/workforce-allocations-to-delius/deploy/templates/initial-allocations-report.yaml +++ b/projects/workforce-allocations-to-delius/deploy/templates/initial-allocations-report.yaml @@ -14,11 +14,11 @@ data: echo Getting HMPPS Auth token... hmpps_auth_token=$(curl -fsSL -XPOST -u "$CLIENT_ID:$CLIENT_SECRET" '{{ index .Values "generic-service" "env" "SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_HMPPS-AUTH_TOKEN-URI" }}?grant_type=client_credentials' | jq -r .access_token) echo Downloading report... - curl -fsSL -H "Authorization: Bearer $hmpps_auth_token" https://{{ index .Values "generic-service" "ingress" "host" }}/initial-allocations.csv > "/tmp/$filename" + curl -fsSL -H "Authorization: Bearer $hmpps_auth_token" http://workforce-allocations-to-delius/initial-allocations.csv > "/tmp/$filename" echo Downloaded report with $(wc -l < "/tmp/$filename") rows echo Starting file upload... - file_details=$(curl -fsSL -XPOST -F "token=$SLACK_TOKEN" -F "filename=$filename" -F 'snippet_type=csv' -F "length=$(wc -c < "/tmp/$filename")" https://slack.com/api/files.getUploadURLExternal) + file_details=$(curl -fsSL -XPOST -F "token=$SLACK_TOKEN" -F "filename=$filename" -F "length=$(wc -c < "/tmp/$filename")" https://slack.com/api/files.getUploadURLExternal) echo Got file upload details: "$file_details" file_id=$(echo "$file_details" | jq -r .file_id) upload_url=$(echo "$file_details" | jq -r .upload_url) diff --git a/projects/workforce-allocations-to-delius/deploy/values.yaml b/projects/workforce-allocations-to-delius/deploy/values.yaml index 23ee145709..6e0786dfbc 100644 --- a/projects/workforce-allocations-to-delius/deploy/values.yaml +++ b/projects/workforce-allocations-to-delius/deploy/values.yaml @@ -2,6 +2,7 @@ # Values here are the same across all environments # An additional set of default values can be found in templates/helm-defaults.yml, which is the same across all projects generic-service: + productId: HMPPS518 nameOverride: workforce-allocations-to-delius serviceAccountName: workforce-allocations-to-delius diff --git a/projects/workforce-allocations-to-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/InitialAllocationIntegrationTest.kt b/projects/workforce-allocations-to-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/InitialAllocationIntegrationTest.kt index ec7b3755a1..6de456023f 100644 --- a/projects/workforce-allocations-to-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/InitialAllocationIntegrationTest.kt +++ b/projects/workforce-allocations-to-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/InitialAllocationIntegrationTest.kt @@ -6,9 +6,9 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.MvcResult import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get -import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content -import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.* import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.withToken @AutoConfigureMockMvc @@ -21,6 +21,8 @@ class InitialAllocationIntegrationTest { fun `returns csv report`() { mockMvc .perform(get("/initial-allocations.csv").accept("text/csv").withToken()) + .andExpect(request().asyncStarted()) + .andDo(MvcResult::getAsyncResult) .andExpect(status().is2xxSuccessful) .andExpect(content().contentTypeCompatibleWith("text/csv;charset=UTF-8")) .andExpect( diff --git a/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/InitialAllocationResource.kt b/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/InitialAllocationResource.kt index 44648505df..f48daa66ee 100644 --- a/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/InitialAllocationResource.kt +++ b/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/resource/InitialAllocationResource.kt @@ -1,21 +1,23 @@ package uk.gov.justice.digital.hmpps.api.resource import io.swagger.v3.oas.annotations.Operation +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity import org.springframework.security.access.prepost.PreAuthorize import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RestController -import uk.gov.justice.digital.hmpps.config.CsvMapperConfig.csvMapper -import uk.gov.justice.digital.hmpps.integrations.delius.allocations.InitialAllocation -import uk.gov.justice.digital.hmpps.integrations.delius.allocations.InitialAllocationRepository +import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody +import uk.gov.justice.digital.hmpps.service.InitialAllocationService @RestController class InitialAllocationResource( - private val initialAllocationRepository: InitialAllocationRepository + private val initialAllocationService: InitialAllocationService ) { - @PreAuthorize("hasRole('PROBATION_API__WORKFORCE_ALLOCATIONS__CASE_DETAIL')") @Operation(summary = "A report of all allocations created by either the Manage a Workforce Allocation tool or Delius, since the start of 2024.") @GetMapping("/initial-allocations.csv", produces = ["text/csv"]) - fun getInitialAllocations(): String = csvMapper - .writer(csvMapper.schemaFor(InitialAllocation::class.java).withHeader()) - .writeValueAsString(initialAllocationRepository.findAllInitialAllocations()) + @PreAuthorize("hasRole('PROBATION_API__WORKFORCE_ALLOCATIONS__CASE_DETAIL')") + fun getInitialAllocations(): ResponseEntity = ResponseEntity.ok() + .contentType(MediaType.parseMediaType("text/csv")) + .header("Content-Disposition", "attachment; filename=initial-allocations.csv") + .body(StreamingResponseBody { initialAllocationService.writeInitialAllocations(it) }) } diff --git a/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/allocations/InitialAllocation.kt b/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/allocations/InitialAllocation.kt index 86571326cb..8a884fe7ae 100644 --- a/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/allocations/InitialAllocation.kt +++ b/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/allocations/InitialAllocation.kt @@ -8,6 +8,7 @@ import org.springframework.data.jpa.repository.Query import org.springframework.stereotype.Repository import uk.gov.justice.digital.hmpps.integrations.delius.person.Person import java.time.LocalDate +import java.util.stream.Stream @JsonPropertyOrder( "crn", @@ -90,5 +91,5 @@ interface InitialAllocationRepository : JpaRepository { """, nativeQuery = true ) - fun findAllInitialAllocations(startDate: LocalDate = LocalDate.ofYearDay(2024, 1)): List + fun findAllInitialAllocations(startDate: LocalDate = LocalDate.ofYearDay(2024, 1)): Stream } diff --git a/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/InitialAllocationService.kt b/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/InitialAllocationService.kt new file mode 100644 index 0000000000..07b9b27537 --- /dev/null +++ b/projects/workforce-allocations-to-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/InitialAllocationService.kt @@ -0,0 +1,21 @@ +package uk.gov.justice.digital.hmpps.service + +import jakarta.transaction.Transactional +import org.springframework.stereotype.Service +import uk.gov.justice.digital.hmpps.config.CsvMapperConfig.csvMapper +import uk.gov.justice.digital.hmpps.integrations.delius.allocations.InitialAllocation +import uk.gov.justice.digital.hmpps.integrations.delius.allocations.InitialAllocationRepository +import java.io.OutputStream +import kotlin.streams.asSequence + +@Service +class InitialAllocationService(private val initialAllocationRepository: InitialAllocationRepository) { + @Transactional + fun writeInitialAllocations(outputStream: OutputStream) { + val results = initialAllocationRepository.findAllInitialAllocations().asSequence() + csvMapper + .writer(csvMapper.schemaFor(InitialAllocation::class.java).withHeader()) + .writeValues(outputStream.bufferedWriter()) + .use { writer -> results.forEach(writer::write) } + } +} diff --git a/projects/workforce-allocations-to-delius/src/main/resources/application.yml b/projects/workforce-allocations-to-delius/src/main/resources/application.yml index 1d7cbf6e21..9e06e357cc 100644 --- a/projects/workforce-allocations-to-delius/src/main/resources/application.yml +++ b/projects/workforce-allocations-to-delius/src/main/resources/application.yml @@ -42,6 +42,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/script/start-service-pod.sh b/script/start-service-pod.sh new file mode 100755 index 0000000000..7b1bc03d6f --- /dev/null +++ b/script/start-service-pod.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail +## +## Start a long-running Kubernetes pod in a given namespace. +## +## Example usage: +## NAMESPACE=hmpps-probation-integration POD_NAME="$USER" ./script/start-service-pod.sh +## + +[ -z "$POD_NAME" ] && echo "Missing POD_NAME" && exit 1 +[ -z "$NAMESPACE" ] && echo "Missing NAMESPACE" && exit 1 + +echo "Starting service pod '$POD_NAME'" +function delete_pod() { kubectl --namespace="$NAMESPACE" delete pod "$POD_NAME"; } +trap delete_pod SIGTERM SIGINT + +kubectl run "$POD_NAME" --namespace="$NAMESPACE" --image=ghcr.io/ministryofjustice/hmpps-devops-tools:latest -- sleep infinity +kubectl wait --namespace="$NAMESPACE" --for=condition=ready pod "$POD_NAME" + +echo "Service pod is ready" \ No newline at end of file diff --git a/script/update-service-catalogue.sh b/script/update-service-catalogue.sh new file mode 100755 index 0000000000..47a7d955eb --- /dev/null +++ b/script/update-service-catalogue.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +set -euo pipefail +## +## Add a new project to the service catalogue. +## +## Example usage: +## PROJECT_NAME=approved-premises-and-delius ./script/update-service-catalogue.sh +## + +[ -z "$PROJECT_NAME" ] && echo "Missing PROJECT_NAME" && exit 1 +[ -z "$SERVICE_CATALOGUE_API_KEY" ] && echo "Missing SERVICE_CATALOGUE_API_KEY" && exit 1 + +api_url="https://service-catalogue.hmpps.service.justice.gov.uk/v1" +product_code="HMPPS518" +product_id=$(curl -fsS -H "Authorization: Bearer $SERVICE_CATALOGUE_API_KEY" "$api_url/products?filters\[p_id\]=$product_code" | jq -r '.data[0].id // ""') +component=$(curl -fsS -H "Authorization: Bearer $SERVICE_CATALOGUE_API_KEY" "$api_url/components?filters\[name\]=$PROJECT_NAME") + +# Get ids for existing environments +ENVIRONMENTS=${ENVIRONMENTS:-[]} +for env in dev preprod prod; do + env_id=$(echo "$component" | jq -r '.data[0].environments | select(.name == $env) | .id' --arg env "$env") + namespace_id=$(curl -fsS -H "Authorization: Bearer $SERVICE_CATALOGUE_API_KEY" "$api_url/namespaces?filters\[name\]=hmpps-probation-integration-services-$env" | jq '.data[0].id') + if [ -n "$env_id" ]; then ENVIRONMENTS=$(echo "$ENVIRONMENTS" | jq -r 'map(select(.name == $env) += {"id": $env_id})' --arg env "$env" --arg env_id "$env_id"); fi + if [ -n "$namespace_id" ]; then ENVIRONMENTS=$(echo "$ENVIRONMENTS" | jq -r 'map(select(.name == $env) += {"ns": $namespace_id})' --arg env "$env" --arg namespace_id "$namespace_id"); fi +done + +data=$(jq -n '{"data": $ARGS.named}' \ + --arg product "$product_id" \ + --arg name "$PROJECT_NAME" \ + --arg title "$PROJECT_TITLE" \ + --arg github_repo hmpps-probation-integration-services \ + --arg part_of_monorepo true \ + --arg path_to_project "projects/$PROJECT_NAME" \ + --arg path_to_helm_dir "projects/$PROJECT_NAME/deploy" \ + --argjson environments "$ENVIRONMENTS" \ + --argjson jira_project_keys '["PI"]' +) + +component_id=$(echo "$component" | jq -r '.data[0].id // ""') +if [ -z "$component_id" ]; then + echo "Adding component $PROJECT_NAME to hmpps-service-catalogue" + curl -XPOST -fsS -H "Authorization: Bearer $SERVICE_CATALOGUE_API_KEY" "$api_url/components" --json "$data" +else + echo "Updating component $PROJECT_NAME ($component_id) in hmpps-service-catalogue" + curl -XPUT -fsS -H "Authorization: Bearer $SERVICE_CATALOGUE_API_KEY" "$api_url/components/$component_id" --json "$data" +fi + +echo "Done: https://developer-portal.hmpps.service.justice.gov.uk/components/$PROJECT_NAME" \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 0445f66e40..089ac5711f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -87,9 +87,7 @@ dependencyResolutionManagement { ) bundle("telemetry", listOf("insights", "opentelemetry-annotations", "sentry")) library("springdoc", "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0") - library("wiremock", "org.wiremock:wiremock-standalone:3.5.4") - library("mapstruct", "org.mapstruct:mapstruct:1.5.5.Final") - library("mapstructprocessor", "org.mapstruct:mapstruct-processor:1.5.5.Final") + library("wiremock", "org.wiremock:wiremock-standalone:3.6.0") library("flipt", "io.flipt:flipt-java:1.1.1") } } diff --git a/templates/projects/api-client-and-server/deploy/values.yaml b/templates/projects/api-client-and-server/deploy/values.yaml index 6ddbfe7d58..8223b4ceac 100644 --- a/templates/projects/api-client-and-server/deploy/values.yaml +++ b/templates/projects/api-client-and-server/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: $SERVICE_NAME image: diff --git a/templates/projects/api-client-and-server/src/main/resources/application.yml b/templates/projects/api-client-and-server/src/main/resources/application.yml index fe7bee896e..efe98f018c 100644 --- a/templates/projects/api-client-and-server/src/main/resources/application.yml +++ b/templates/projects/api-client-and-server/src/main/resources/application.yml @@ -38,6 +38,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/templates/projects/api-server/deploy/values.yaml b/templates/projects/api-server/deploy/values.yaml index 1780ab6306..aaa8d13633 100644 --- a/templates/projects/api-server/deploy/values.yaml +++ b/templates/projects/api-server/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: $SERVICE_NAME image: diff --git a/templates/projects/api-server/src/main/resources/application.yml b/templates/projects/api-server/src/main/resources/application.yml index 29550606ac..ccd5236345 100644 --- a/templates/projects/api-server/src/main/resources/application.yml +++ b/templates/projects/api-server/src/main/resources/application.yml @@ -28,6 +28,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config spring.config.activate.on-profile: [ "dev", "integration-test" ] diff --git a/templates/projects/message-listener-with-api-client-and-server/deploy/values.yaml b/templates/projects/message-listener-with-api-client-and-server/deploy/values.yaml index 9de69109ee..205eaaa3b5 100644 --- a/templates/projects/message-listener-with-api-client-and-server/deploy/values.yaml +++ b/templates/projects/message-listener-with-api-client-and-server/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: $SERVICE_NAME serviceAccountName: $SERVICE_NAME diff --git a/templates/projects/message-listener-with-api-client-and-server/src/main/resources/application.yml b/templates/projects/message-listener-with-api-client-and-server/src/main/resources/application.yml index 851f626c00..ca73533f09 100644 --- a/templates/projects/message-listener-with-api-client-and-server/src/main/resources/application.yml +++ b/templates/projects/message-listener-with-api-client-and-server/src/main/resources/application.yml @@ -38,6 +38,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/templates/projects/message-listener-with-api-client/deploy/values.yaml b/templates/projects/message-listener-with-api-client/deploy/values.yaml index 9de69109ee..205eaaa3b5 100644 --- a/templates/projects/message-listener-with-api-client/deploy/values.yaml +++ b/templates/projects/message-listener-with-api-client/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: $SERVICE_NAME serviceAccountName: $SERVICE_NAME diff --git a/templates/projects/message-listener-with-api-client/src/main/resources/application.yml b/templates/projects/message-listener-with-api-client/src/main/resources/application.yml index 08cac598a8..29029558dc 100644 --- a/templates/projects/message-listener-with-api-client/src/main/resources/application.yml +++ b/templates/projects/message-listener-with-api-client/src/main/resources/application.yml @@ -36,6 +36,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/templates/projects/message-listener/deploy/values.yaml b/templates/projects/message-listener/deploy/values.yaml index 072f4bed6c..4ee0ff2956 100644 --- a/templates/projects/message-listener/deploy/values.yaml +++ b/templates/projects/message-listener/deploy/values.yaml @@ -1,5 +1,6 @@ # Common values generic-service: + productId: HMPPS518 nameOverride: $SERVICE_NAME serviceAccountName: $SERVICE_NAME diff --git a/templates/projects/message-listener/src/main/resources/application.yml b/templates/projects/message-listener/src/main/resources/application.yml index 1da4715011..5bc371c72f 100644 --- a/templates/projects/message-listener/src/main/resources/application.yml +++ b/templates/projects/message-listener/src/main/resources/application.yml @@ -26,6 +26,8 @@ management: exposure.include: [ "health", "info" ] endpoint.health.show-details: always +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 + --- # Shared dev/test config diff --git a/tools/ingress-testing/api-client/src/main/resources/application.yml b/tools/ingress-testing/api-client/src/main/resources/application.yml index 07583a182c..d6cab15b8d 100644 --- a/tools/ingress-testing/api-client/src/main/resources/application.yml +++ b/tools/ingress-testing/api-client/src/main/resources/application.yml @@ -5,3 +5,5 @@ management: base-path: / exposure.include: [ "health", "info" ] endpoint.health.show-details: always + +info.productId: HMPPS518 # https://developer-portal.hmpps.service.justice.gov.uk/products/185 diff --git a/tools/ingress-testing/api-server/deploy/values.yaml b/tools/ingress-testing/api-server/deploy/values.yaml index 5d0c7ed3f1..05ca808dbc 100644 --- a/tools/ingress-testing/api-server/deploy/values.yaml +++ b/tools/ingress-testing/api-server/deploy/values.yaml @@ -1,5 +1,6 @@ --- generic-service: + productId: HMPPS518 nameOverride: ingress-test replicaCount: 2