diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/jpa/entity/cas1/Cas1PremisesSearchRepository.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/jpa/entity/cas1/Cas1PremisesSearchRepository.kt index 8789e019e0..3741bb7020 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/jpa/entity/cas1/Cas1PremisesSearchRepository.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/jpa/entity/cas1/Cas1PremisesSearchRepository.kt @@ -61,13 +61,15 @@ FROM p.postcode AS postcode, aa.id AS ap_area_id, aa.name AS ap_area_name, - ARRAY_AGG (characteristics.property_name) as characteristics + ARRAY_AGG (DISTINCT characteristics.property_name) as characteristics FROM approved_premises ap INNER JOIN premises p ON ap.premises_id = p.id INNER JOIN probation_regions pr ON p.probation_region_id = pr.id INNER JOIN ap_areas aa ON pr.ap_area_id = aa.id + LEFT OUTER JOIN rooms ON rooms.premises_id = p.id LEFT OUTER JOIN premises_characteristics premises_chars ON premises_chars.premises_id = p.id - LEFT OUTER JOIN characteristics ON characteristics.id = premises_chars.characteristic_id + LEFT OUTER JOIN room_characteristics room_chars ON room_chars.room_id = rooms.id + LEFT OUTER JOIN characteristics ON (characteristics.id IN (premises_chars.characteristic_id,room_chars.characteristic_id)) WHERE ap.supports_space_bookings = true AND ap.gender = #SPECIFIED_GENDER# diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/service/cas1/Cas1SpaceSearchService.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/service/cas1/Cas1SpaceSearchService.kt index 5d86b7e8d7..dd308ef462 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/service/cas1/Cas1SpaceSearchService.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/service/cas1/Cas1SpaceSearchService.kt @@ -28,10 +28,12 @@ class Cas1SpaceSearchService( val requiredCharacteristics = getRequiredCharacteristics(searchParameters.requirements) - return getCandidatePremises( - searchParameters.targetPostcodeDistrict, - requiredCharacteristics, + return spaceSearchRepository.findAllPremisesWithCharacteristicsByDistance( + targetPostcodeDistrict = searchParameters.targetPostcodeDistrict, + approvedPremisesType = requiredCharacteristics.apType, isWomensPremises = application.isWomensApplication!!, + premisesCharacteristics = requiredCharacteristics.groupedCharacteristics.premisesCharacteristics, + roomCharacteristics = requiredCharacteristics.groupedCharacteristics.roomCharacteristics, ) } @@ -54,20 +56,6 @@ class Cas1SpaceSearchService( ) } - private fun getCandidatePremises( - targetPostcodeDistrict: String, - requiredCharacteristics: RequiredCharacteristics, - isWomensPremises: Boolean, - ): List { - return spaceSearchRepository.findAllPremisesWithCharacteristicsByDistance( - targetPostcodeDistrict, - requiredCharacteristics.apType, - isWomensPremises, - requiredCharacteristics.groupedCharacteristics.premisesCharacteristics, - requiredCharacteristics.groupedCharacteristics.roomCharacteristics, - ) - } - private fun CharacteristicEntity.isPremisesCharacteristic(): Boolean = this.serviceMatches(ServiceName.approvedPremises.value) && this.modelMatches("premises") diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/transformer/cas1/Cas1SpaceSearchResultsTransformer.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/transformer/cas1/Cas1SpaceSearchResultsTransformer.kt index 7729016be9..fa61145468 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/transformer/cas1/Cas1SpaceSearchResultsTransformer.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/transformer/cas1/Cas1SpaceSearchResultsTransformer.kt @@ -2,8 +2,8 @@ package uk.gov.justice.digital.hmpps.approvedpremisesapi.transformer.cas1 import org.slf4j.LoggerFactory import org.springframework.stereotype.Component -import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.Cas1PremiseCharacteristic import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.Cas1PremisesSearchResultSummary +import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.Cas1SpaceCharacteristic import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.Cas1SpaceSearchParameters import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.Cas1SpaceSearchResults import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.NamedId @@ -39,9 +39,9 @@ class Cas1SpaceSearchResultsTransformer { premisesCharacteristics = emptyList(), characteristics = candidatePremises.characteristics.mapNotNull { try { - Cas1PremiseCharacteristic.valueOf(it) + Cas1SpaceCharacteristic.valueOf(it) } catch (e: IllegalArgumentException) { - log.warn("Couldn't find an enum entry for propertyName $it") + log.warn("Couldn't find a Cas1SpaceCharacteristic enum entry for propertyName $it") null } }, diff --git a/src/main/resources/static/cas1-schemas.yml b/src/main/resources/static/cas1-schemas.yml index 00fddec610..60e8bb00d2 100644 --- a/src/main/resources/static/cas1-schemas.yml +++ b/src/main/resources/static/cas1-schemas.yml @@ -67,8 +67,9 @@ components: $ref: '_shared.yml#/components/schemas/CharacteristicPair' characteristics: type: array + description: "Room and premise characteristics" items: - $ref: '#/components/schemas/Cas1PremiseCharacteristic' + $ref: '#/components/schemas/Cas1SpaceCharacteristic' required: - id - apType @@ -140,30 +141,6 @@ components: required: - startInclusive - endInclusive - Cas1PremiseCharacteristic: - type: string - description: All premise characteristics - enum: - - acceptsChildSexOffenders - - acceptsHateCrimeOffenders - - acceptsNonSexualChildOffenders - - acceptsSexOffenders - - additionalRestrictions - - hasBrailleSignage - - hasHearingLoop - - hasLift - - hasStepFreeAccessToCommunalAreas - - hasTactileFlooring - - hasWheelChairAccessibleBathrooms - - hasWideAccessToCommunalAreas - - hasWideStepFreeAccess - - isCatered - - isESAP - - isIAP - - isPIPE - - isRecoveryFocussed - - isSuitableForVulnerable - - isSemiSpecialistMentalHealth Cas1SpaceCharacteristic: type: string description: All of the characteristics of both premises and rooms diff --git a/src/main/resources/static/codegen/built-cas1-api-spec.yml b/src/main/resources/static/codegen/built-cas1-api-spec.yml index 0f84f60265..d44c756e67 100644 --- a/src/main/resources/static/codegen/built-cas1-api-spec.yml +++ b/src/main/resources/static/codegen/built-cas1-api-spec.yml @@ -6117,8 +6117,9 @@ components: $ref: '#/components/schemas/CharacteristicPair' characteristics: type: array + description: "Room and premise characteristics" items: - $ref: '#/components/schemas/Cas1PremiseCharacteristic' + $ref: '#/components/schemas/Cas1SpaceCharacteristic' required: - id - apType @@ -6190,30 +6191,6 @@ components: required: - startInclusive - endInclusive - Cas1PremiseCharacteristic: - type: string - description: All premise characteristics - enum: - - acceptsChildSexOffenders - - acceptsHateCrimeOffenders - - acceptsNonSexualChildOffenders - - acceptsSexOffenders - - additionalRestrictions - - hasBrailleSignage - - hasHearingLoop - - hasLift - - hasStepFreeAccessToCommunalAreas - - hasTactileFlooring - - hasWheelChairAccessibleBathrooms - - hasWideAccessToCommunalAreas - - hasWideStepFreeAccess - - isCatered - - isESAP - - isIAP - - isPIPE - - isRecoveryFocussed - - isSuitableForVulnerable - - isSemiSpecialistMentalHealth Cas1SpaceCharacteristic: type: string description: All of the characteristics of both premises and rooms diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/integration/cas1/Cas1SpaceSearchTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/integration/cas1/Cas1SpaceSearchTest.kt index 0e625aa69d..bc97837e0c 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/integration/cas1/Cas1SpaceSearchTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/approvedpremisesapi/integration/cas1/Cas1SpaceSearchTest.kt @@ -7,7 +7,6 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.EnumSource import org.springframework.beans.factory.annotation.Autowired import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.ApType -import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.Cas1PremiseCharacteristic import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.Cas1SpaceCharacteristic import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.Cas1SpaceSearchParameters import uk.gov.justice.digital.hmpps.approvedpremisesapi.api.model.Cas1SpaceSearchRequirements @@ -63,6 +62,17 @@ class Cas1SpaceSearchTest : InitialiseDatabasePerClassTestBase() { withLatitude((it * -0.01) - 0.08) withLongitude((it * 0.01) + 51.49) withSupportsSpaceBookings(true) + withCharacteristicsList(emptyList()) + } + + val premiseWithCharacteristics = approvedPremisesEntityFactory.produceAndPersist { + withYieldedProbationRegion { givenAProbationRegion() } + withYieldedLocalAuthorityArea { + localAuthorityEntityFactory.produceAndPersist() + } + withLatitude(1.0) + withLongitude(2.0) + withSupportsSpaceBookings(true) withCharacteristicsList( listOf( characteristicRepository.findCas1ByPropertyName("hasWideAccessToCommunalAreas")!!, @@ -70,6 +80,13 @@ class Cas1SpaceSearchTest : InitialiseDatabasePerClassTestBase() { characteristicRepository.findCas1ByPropertyName("hasLift")!!, ), ) + }.also { + roomEntityFactory.produceAndPersist { + withPremises(it) + withCharacteristics( + characteristicRepository.findCas1ByPropertyName("hasEnSuite")!!, + ) + } } // premise that doesn't support space bookings @@ -105,20 +122,24 @@ class Cas1SpaceSearchTest : InitialiseDatabasePerClassTestBase() { val results = response.responseBody.blockFirst()!! - assertThat(results.resultsCount).isEqualTo(5) + assertThat(results.resultsCount).isEqualTo(6) assertThat(results.searchCriteria).isEqualTo(searchParameters) - val expectedCharacteristics = listOf( - Cas1PremiseCharacteristic.hasWideAccessToCommunalAreas, - Cas1PremiseCharacteristic.hasWideStepFreeAccess, - Cas1PremiseCharacteristic.hasLift, + assertThatResultMatches(results.results[0], premises[0], expectedCharacteristics = emptyList()) + assertThatResultMatches(results.results[1], premises[1], expectedCharacteristics = emptyList()) + assertThatResultMatches(results.results[2], premises[2], expectedCharacteristics = emptyList()) + assertThatResultMatches(results.results[3], premises[3], expectedCharacteristics = emptyList()) + assertThatResultMatches(results.results[4], premises[4], expectedCharacteristics = emptyList()) + assertThatResultMatches( + results.results[5], + premiseWithCharacteristics, + expectedCharacteristics = listOf( + Cas1SpaceCharacteristic.hasWideAccessToCommunalAreas, + Cas1SpaceCharacteristic.hasWideStepFreeAccess, + Cas1SpaceCharacteristic.hasLift, + Cas1SpaceCharacteristic.hasEnSuite, + ), ) - - assertThatResultMatches(results.results[0], premises[0], expectedCharacteristics = expectedCharacteristics) - assertThatResultMatches(results.results[1], premises[1], expectedCharacteristics = expectedCharacteristics) - assertThatResultMatches(results.results[2], premises[2], expectedCharacteristics = expectedCharacteristics) - assertThatResultMatches(results.results[3], premises[3], expectedCharacteristics = expectedCharacteristics) - assertThatResultMatches(results.results[4], premises[4], expectedCharacteristics = expectedCharacteristics) } } @@ -341,7 +362,7 @@ class Cas1SpaceSearchTest : InitialiseDatabasePerClassTestBase() { actual: Cas1SpaceSearchResult, expected: ApprovedPremisesEntity, expectedApType: ApType = ApType.normal, - expectedCharacteristics: List? = null, + expectedCharacteristics: List? = null, ) { assertThat(actual.spacesAvailable).isEmpty() assertThat(actual.distanceInMiles).isGreaterThan(0f.toBigDecimal())