diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/controller/ReferralController.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/controller/ReferralController.kt index 21e17f980..7587f07a7 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/controller/ReferralController.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/controller/ReferralController.kt @@ -1,6 +1,5 @@ package uk.gov.justice.digital.hmpps.hmppsinterventionsservice.controller -import ServiceProviderSentReferralSummaryDTO import com.fasterxml.jackson.annotation.JsonView import com.microsoft.applicationinsights.TelemetryClient import jakarta.annotation.Nullable @@ -22,7 +21,6 @@ import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.authorization.Clie import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.authorization.UserMapper import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.controller.mappers.CancellationReasonMapper import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.dto.ActionPlanSummaryDTO -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.dto.DashboardType import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.dto.ReferralAssignmentDTO import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.dto.ReferralDetailsDTO import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.dto.SentReferralDTO @@ -118,27 +116,6 @@ class ReferralController( } } - @Deprecated(message = "This is a temporary solution to by-pass the extremely long wait times in production that occurs with /sent-referrals") - @JsonView(Views.SentReferral::class) - @GetMapping("/sent-referrals/summary/service-provider") - fun getServiceProviderSentReferralsSummary( - authentication: JwtAuthenticationToken, - @Nullable - @RequestParam(name = "dashboardType", required = false) - dashboardTypeSelection: String?, - ): List { - val user = userMapper.fromToken(authentication) - val dashboardType = dashboardTypeSelection?.let { DashboardType.valueOf(it) } - return referralService.getServiceProviderSummaries(user, dashboardType) - .map { ServiceProviderSentReferralSummaryDTO.from(it) }.also { - telemetryClient.trackEvent( - "ServiceProviderReferralSummaryRequest", - null, - mutableMapOf("totalNumberOfReferrals" to it.size.toDouble()), - ) - } - } - @GetMapping("/service-category/{id}") fun getServiceCategoryByID(@PathVariable id: UUID): ServiceCategoryFullDTO { return serviceCategoryService.getServiceCategoryByID(id) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/jpa/repository/ReferralSummaryRepository.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/jpa/repository/ReferralSummaryRepository.kt index b0453d232..2c0e69cb1 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/jpa/repository/ReferralSummaryRepository.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/jpa/repository/ReferralSummaryRepository.kt @@ -1,12 +1,8 @@ package uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.repository import org.springframework.data.domain.Page -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.dto.DashboardType -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.AuthUser -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.ServiceProviderSentReferralSummary import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.service.ReferralSummaryQuery interface ReferralSummaryRepository { - fun getSentReferralSummaries(authUser: AuthUser, serviceProviders: List, dashboardType: DashboardType? = null): List fun getReferralSummaries(referralSummaryQuery: ReferralSummaryQuery): Page } diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/jpa/repository/ReferralSummaryRepositoryImpl.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/jpa/repository/ReferralSummaryRepositoryImpl.kt index e0cecaa1d..a6c28e531 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/jpa/repository/ReferralSummaryRepositoryImpl.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/jpa/repository/ReferralSummaryRepositoryImpl.kt @@ -8,11 +8,8 @@ import org.springframework.data.domain.PageImpl import org.springframework.data.domain.PageRequest import org.springframework.data.domain.Sort import org.springframework.stereotype.Component -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.dto.DashboardType -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.AuthUser import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.DynamicFrameworkContract import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.PersonCurrentLocationType -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.ServiceProviderSentReferralSummary import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.service.ReferralSummaryQuery import java.sql.Date import java.time.Instant @@ -20,7 +17,6 @@ import java.time.LocalDate import java.time.OffsetDateTime import java.time.ZoneId import java.util.UUID -import kotlin.contracts.contract data class ReferralSummary( val referralId: UUID, @@ -69,56 +65,6 @@ class ReferralSummaryRepositoryImpl : ReferralSummaryRepository { @PersistenceContext private lateinit var entityManager: EntityManager - private fun summariesQuery(customCriteria: String?): String { - val dashboardRestrictionCriteria = customCriteria?.let { " $customCriteria " } ?: "" - return """select - referralId, - sentAt, - referenceNumber, - interventionTitle, - dynamicFrameworkContractId, - assignedToUserName, - serviceUserFirstName, - serviceUserLastName, - endOfServiceReportId, - endOfServiceReportSubmittedAt, - concludedAt from ( - select - cast(r.id as varchar) AS referralId, - cast(r.sent_at as TIMESTAMP WITH TIME ZONE) as sentAt, - r.reference_number as referenceNumber, - cast(dfc.id as varchar) as dynamicFrameworkContractId, - au.user_name as assignedToUserName, - i.title as interventionTitle, - rsud.first_name as serviceUserFirstName, - rsud.last_name as serviceUserLastName, - cast(eosr.id as varchar) as endOfServiceReportId, - cast(eosr.submitted_at as TIMESTAMP WITH TIME ZONE) as endOfServiceReportSubmittedAt, - row_number() over(partition by r.id order by ra.assigned_at desc) as assigned_at_desc_seq, - cast(r.concluded_at as TIMESTAMP WITH TIME ZONE) as concludedAt - from referral r - inner join intervention i on i.id = r.intervention_id - left join referral_service_user_data rsud on rsud.referral_id = r.id - inner join dynamic_framework_contract dfc on dfc.id = i.dynamic_framework_contract_id - left join dynamic_framework_contract_sub_contractor dfcsc on dfcsc.dynamic_framework_contract_id = dfc.id - left join referral_assignments ra on ra.referral_id = r.id - left join auth_user au on au.id = ra.assigned_to_id - left join end_of_service_report eosr on eosr.referral_id = r.id - left outer join action_plan ap on ap.referral_id = r.id - left outer join appointment app - left join supplier_assessment_appointment saa on saa.appointment_id = app.id - on app.referral_id = r.id - where - r.sent_at is not null - and ( dfc.prime_provider_id in :serviceProviders or dfcsc.subcontractor_provider_id in :serviceProviders ) - and not ( - (r.concluded_At is not null and r.end_Requested_At is not null and eosr.id is null) -- cancelled - and app.attendance_submitted_at is null -- supplier assessment feedback not submitted - and ap.submitted_at is null -- action plan has not been submitted - ) -- filter out referrals that are cancelled with SAA feedback not completed yet or cancelled with no action plan submitted -) a where assigned_at_desc_seq = 1 $dashboardRestrictionCriteria""" - } - private fun referralSummaryQuery(customCriteria: String?): String { val dashboardRestrictionCriteria = customCriteria?.let { " $customCriteria " } ?: "" return """ @@ -204,30 +150,6 @@ WHERE assigned_at_desc_seq = 1 """.trimIndent() } - override fun getSentReferralSummaries(authUser: AuthUser, serviceProviders: List, dashboardType: DashboardType?): List { - val query = entityManager.createNativeQuery(summariesQuery(constructCustomCriteria(dashboardType))) - query.setParameter("serviceProviders", serviceProviders) - if (dashboardType == DashboardType.MyCases) { - query.setParameter("username", authUser.userName) - } - val result = query.resultList as List> - val summaries: MutableList = mutableListOf() - result.forEach { row -> - val referralId = row[0] as String - val sentAt = row[1] as Instant - val referenceNumber = row[2] as String - val interventionTitle = row[3] as String - val dynamicFrameWorkContractId = row[4] as String - val assignedToUserName = row[5] as String? - val serviceUserFirstName = row[6] as String? - val serviceUserLastName = row[7] as String? - val endOfServiceReportId = (row[8] as String?)?.let { UUID.fromString(it) } - val endOfServiceReportSubmittedAt = row[9] as Instant? - summaries.add(ServiceProviderSentReferralSummary(referralId, sentAt, referenceNumber, interventionTitle, dynamicFrameWorkContractId, assignedToUserName, serviceUserFirstName, serviceUserLastName, endOfServiceReportId, endOfServiceReportSubmittedAt)) - } - return summaries - } - override fun getReferralSummaries( referralSummaryQuery: ReferralSummaryQuery, ): Page { @@ -473,16 +395,6 @@ WHERE assigned_at_desc_seq = 1 } } - private fun constructCustomCriteria(dashboardType: DashboardType?): String? { - return when (dashboardType) { - DashboardType.MyCases -> "and assignedToUserName = :username and concludedAt is null " - DashboardType.OpenCases -> "and concludedAt is null " - DashboardType.UnassignedCases -> "and assignedToUserName is null and concludedAt is null" - DashboardType.CompletedCases -> "and concludedAt is not null " - null -> null - } - } - private fun instantToOffsetNotNull(instant: Instant?): OffsetDateTime { val resolved = instant ?: Instant.now() return OffsetDateTime.ofInstant(resolved, ZoneId.systemDefault()) diff --git a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/service/ReferralService.kt b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/service/ReferralService.kt index b700cdff6..baa0fea6b 100644 --- a/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/service/ReferralService.kt +++ b/src/main/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/service/ReferralService.kt @@ -7,7 +7,6 @@ import org.springframework.context.annotation.Lazy import org.springframework.data.domain.Pageable import org.springframework.data.jpa.domain.Specification import org.springframework.data.jpa.domain.Specification.not -import org.springframework.data.jpa.domain.Specification.where import org.springframework.data.repository.findByIdOrNull import org.springframework.http.HttpStatus import org.springframework.stereotype.Service @@ -19,7 +18,6 @@ import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.authorization.Refe import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.authorization.ServiceProviderAccessScopeMapper import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.authorization.UserTypeChecker import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.config.AccessError -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.dto.DashboardType import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.dto.UpdateReferralDetailsDTO import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.dto.WithdrawReferralRequestDTO import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.events.ReferralEventPublisher @@ -29,7 +27,6 @@ import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Dynamic import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Referral import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.ReferralAssignment import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.ReferralDetails -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.ServiceProviderSentReferralSummary import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Status import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.WithdrawalReason import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.repository.AuthUserRepository @@ -43,7 +40,6 @@ import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.repository.Ref import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.repository.SentReferralSummariesRepository import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.repository.ServiceCategoryRepository import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.repository.WithdrawalReasonRepository -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.specification.ReferralSpecifications import java.time.OffsetDateTime import java.util.UUID @@ -173,75 +169,11 @@ class ReferralService( throw AccessError(user, "unsupported user type", listOf("logins from ${user.authSource} are not supported")) } - fun getServiceProviderSummaries(user: AuthUser, dashboardType: DashboardType? = null): List { - if (userTypeChecker.isServiceProviderUser(user)) { - return getSentReferralSummariesForServiceProviderUser(user, dashboardType) - } - throw AccessError(user, "unsupported user type", listOf("logins from ${user.authSource} are not supported")) - } - private fun applyOptionalConjunction(existingSpec: Specification, predicate: Boolean?, specToJoin: Specification): Specification { if (predicate == null) return existingSpec return existingSpec.and(if (predicate) specToJoin else not(specToJoin)) } - private fun getSentReferralSummariesForServiceProviderUser(user: AuthUser, dashboardType: DashboardType?): List { - val serviceProviders = serviceProviderUserAccessScopeMapper.fromUser(user).serviceProviders - val referralSummaries = referralRepository.getSentReferralSummaries(user, serviceProviders = serviceProviders.map { serviceProvider -> serviceProvider.id }, dashboardType) - return referralAccessFilter.serviceProviderReferralSummaries(referralSummaries, user) - } - - private inline fun createSpecification( - concluded: Boolean?, - cancelled: Boolean?, - unassigned: Boolean?, - assignedToUserId: String?, - searchText: String?, - ): Specification { - var findSentReferralsSpec = ReferralSpecifications.sent() - - findSentReferralsSpec = applyOptionalConjunction(findSentReferralsSpec, concluded, ReferralSpecifications.concluded()) - findSentReferralsSpec = applyOptionalConjunction(findSentReferralsSpec, cancelled, ReferralSpecifications.cancelled()) - findSentReferralsSpec = applyOptionalConjunction(findSentReferralsSpec, unassigned, ReferralSpecifications.unassigned()) - assignedToUserId?.let { - findSentReferralsSpec = applyOptionalConjunction(findSentReferralsSpec, true, ReferralSpecifications.currentlyAssignedTo(it)) - } - searchText?.let { - findSentReferralsSpec = applyOptionalConjunction(findSentReferralsSpec, true, searchSpec(searchText)) - } - return findSentReferralsSpec - } - - private fun searchSpec(searchText: String): Specification { - return if (searchText.matches(Regex("[A-Z]{2}[0-9]{4}[A-Z]{2}"))) { - ReferralSpecifications.searchByReferenceNumber(searchText) - } else { - ReferralSpecifications.searchByPoPName(searchText) - } - } - - private fun createSpecificationForProbationPractitionerUser( - user: AuthUser, - sentReferralFilterSpecification: Specification, - ): Specification { - var referralsForPPUser = ReferralSpecifications.createdBy(user) - try { - val serviceUserCRNs = communityAPIOffenderService.getManagedOffendersForDeliusUser(user).map { it.crnNumber } - referralsForPPUser = referralsForPPUser.or(ReferralSpecifications.matchingServiceUserReferrals(serviceUserCRNs)) - } catch (e: WebClientResponseException) { - // don't stop users seeing their own referrals just because delius is not playing nice - logger.error( - "failed to get managed offenders for user {}", - e, - kv("username", user.userName), - ) - } - - // todo: filter out referrals for limited access offenders (LAOs) - val referralSpecification = where(referralsForPPUser).and(sentReferralFilterSpecification) - return referralAccessFilter.probationPractitionerReferrals(referralSpecification, user) - } - private fun crnsAssociatedWithPP( user: AuthUser, ): List { diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/controller/ReferralControllerTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/controller/ReferralControllerTest.kt index b151cb3d1..99184e787 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/controller/ReferralControllerTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/controller/ReferralControllerTest.kt @@ -236,67 +236,6 @@ internal class ReferralControllerTest { } } - @Nested - inner class GetServiceProviderSentReferralsSummary { - private val token = tokenFactory.create() - - @Test - fun `can accept all defined dashboard types`() { - whenever(referralService.getServiceProviderSummaries(any(), any())).thenReturn(emptyList()) - whenever(authUserRepository.save(any())).thenReturn(authUserFactory.create()) - assertThat( - referralController.getServiceProviderSentReferralsSummary( - token, - "MyCases", - ), - ).isNotNull - - assertThat( - referralController.getServiceProviderSentReferralsSummary( - token, - "OpenCases", - ), - ).isNotNull - - assertThat( - referralController.getServiceProviderSentReferralsSummary( - token, - "UnassignedCases", - ), - ).isNotNull - - assertThat( - referralController.getServiceProviderSentReferralsSummary( - token, - "CompletedCases", - ), - ).isNotNull - } - - @Test - fun `returns default list when no dashboardType provided`() { - whenever(referralService.getServiceProviderSummaries(any(), any())).thenReturn(emptyList()) - whenever(authUserRepository.save(any())).thenReturn(authUserFactory.create()) - val result = referralController.getServiceProviderSentReferralsSummary( - token, - null, - ) - assertThat(result).isNotNull - } - - @Test - fun `throws error when invalid dashboardType provided`() { - whenever(referralService.getServiceProviderSummaries(any(), any())).thenReturn(emptyList()) - whenever(authUserRepository.save(any())).thenReturn(authUserFactory.create()) - assertThrows { - referralController.getServiceProviderSentReferralsSummary( - token, - "invalidDashBoardType", - ) - } - } - } - @Test fun `assignSentReferral returns 404 if referral does not exist`() { whenever(referralService.getSentReferralForUser(any(), any())).thenReturn(null) diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/integration/authorization/GetServiceProviderReferralsSummaryEndPoint.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/integration/authorization/GetServiceProviderReferralsSummaryEndPoint.kt deleted file mode 100644 index 1eefdc186..000000000 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/integration/authorization/GetServiceProviderReferralsSummaryEndPoint.kt +++ /dev/null @@ -1,214 +0,0 @@ -package uk.gov.justice.digital.hmpps.hmppsinterventionsservice.integration.authorization - -import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.mockito.kotlin.whenever -import org.springframework.boot.test.mock.mockito.MockBean -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.integration.IntegrationTestBase -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.AuthUser -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.DynamicFrameworkContract -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Referral -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.service.CommunityAPIOffenderService -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.service.HMPPSAuthService -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.util.JwtTokenFactory - -class GetServiceProviderReferralsSummaryEndPoint : IntegrationTestBase() { - - @MockBean - lateinit var mockHmppsAuthService: HMPPSAuthService - - @MockBean lateinit var mockCommunityAPIOffenderService: CommunityAPIOffenderService - - private lateinit var requestFactory: RequestFactory - - private val tokenFactory = JwtTokenFactory() - - @BeforeEach - fun initRequestBuilder() { - requestFactory = RequestFactory(webTestClient, setupAssistant) - } - - private fun setUserGroups(user: AuthUser, groups: List?) { - whenever(mockHmppsAuthService.getUserGroups(user)).thenReturn(groups) - } - - private fun createSentReferral(contract: DynamicFrameworkContract): Referral { - return setupAssistant.createSentReferral(intervention = setupAssistant.createIntervention(dynamicFrameworkContract = contract)) - } - - private fun createEncodedTokenForUser(user: AuthUser): String { - return tokenFactory.createEncodedToken(userID = user.id, userName = user.userName, authSource = user.authSource, roles = listOf("ROLE_CRS_PROVIDER")) - } - - @Test - fun `sp user works for prime provider and has all required contract groups`() { - val user = setupAssistant.createSPUser() - - setUserGroups( - user, - listOf( - "INT_SP_HARMONY_LIVING", - "INT_CR_0001", - "INT_CR_0002", - ), - ) - - listOf( - setupAssistant.createDynamicFrameworkContract( - contractReference = "0001", - primeProviderId = "HARMONY_LIVING", - subContractorServiceProviderIds = emptySet(), - ), - setupAssistant.createDynamicFrameworkContract( - contractReference = "0002", - primeProviderId = "HARMONY_LIVING", - subContractorServiceProviderIds = emptySet(), - ), - ).forEach { - createSentReferral(it) - } - - val token = createEncodedTokenForUser(user) - var response = requestFactory.create(Request.GetServiceProviderReferralsSummary, token).exchange() - response.expectStatus().is2xxSuccessful - response.expectBody().jsonPath("$.length()").isEqualTo(2) - } - - @Test - fun `sp user works for prime and subcontractor providers and has all required contract groups`() { - val user = setupAssistant.createSPUser() - - setUserGroups( - user, - listOf( - "INT_SP_HOME_TRUST", - "INT_CR_0001", - "INT_CR_0002", - ), - ) - - listOf( - setupAssistant.createDynamicFrameworkContract( - contractReference = "0001", - primeProviderId = "HARMONY_LIVING", - subContractorServiceProviderIds = setOf("HOME_TRUST"), - ), - setupAssistant.createDynamicFrameworkContract( - contractReference = "0002", - primeProviderId = "HOME_TRUST", - subContractorServiceProviderIds = emptySet(), - ), - ).forEach { - createSentReferral(it) - } - - val token = createEncodedTokenForUser(user) - var response = requestFactory.create(Request.GetServiceProviderReferralsSummary, token).exchange() - response.expectStatus().is2xxSuccessful - response.expectBody().jsonPath("$.length()").isEqualTo(2) - } - - @Test - fun `sp user works for prime provider but is missing a required contract group`() { - val user = setupAssistant.createSPUser() - - setUserGroups( - user, - listOf( - "INT_SP_HOME_TRUST", - "INT_CR_0003", - ), - ) - - listOf( - setupAssistant.createDynamicFrameworkContract( - contractReference = "0001", - primeProviderId = "HARMONY_LIVING", - subContractorServiceProviderIds = setOf("HOME_TRUST"), - ), - setupAssistant.createDynamicFrameworkContract( - contractReference = "0002", - primeProviderId = "HOME_TRUST", - subContractorServiceProviderIds = emptySet(), - ), - ).forEach { - createSentReferral(it) - } - - // valid contract for the user - but no referrals - setupAssistant.createDynamicFrameworkContract( - contractReference = "0003", - primeProviderId = "HOME_TRUST", - subContractorServiceProviderIds = emptySet(), - ) - - val token = createEncodedTokenForUser(user) - var response = requestFactory.create(Request.GetServiceProviderReferralsSummary, token).exchange() - response.expectStatus().is2xxSuccessful - response.expectBody().jsonPath("$.length()").isEqualTo(0) - } - - @Test - fun `sp user has no valid provider or contract groups`() { - val user = setupAssistant.createSPUser() - - setUserGroups( - user, - listOf( - "INT_SP_HOME_TRUST", - "INT_CR_0999", - ), - ) - - val token = createEncodedTokenForUser(user) - val response = requestFactory.create(Request.GetServiceProviderReferralsSummary, token).exchange() - response.expectStatus().isForbidden - response.expectBody().json( - """ - {"accessErrors": [ - "no valid service provider groups associated with user", - "no valid contract groups associated with user" - ]} - """.trimIndent(), - ) - } - - @Test - fun `nomis users can't access sent referrals`() { - setupAssistant.createSentReferral() - val token = tokenFactory.createEncodedToken("123456", "nomis", "tom", listOf("ROLE_CRS_PROVIDER")) - - val response = requestFactory.create(Request.GetServiceProviderReferralsSummary, token).exchange() - response.expectStatus().isForbidden - response.expectBody().json( - """ - {"accessErrors": ["logins from nomis are not supported"]} - """.trimIndent(), - ) - } - - @Test - fun `users not found in hmpps auth can't access sent referrals'`() { - val user = setupAssistant.createSPUser() - setUserGroups(user, null) - - val referral = setupAssistant.createSentReferral() - val token = createEncodedTokenForUser(user) - - val response = requestFactory.create(Request.GetServiceProviderReferralsSummary, token, referral.id.toString()).exchange() - response.expectStatus().isForbidden - response.expectBody().json( - """ - {"accessErrors": [ - "cannot find user in hmpps auth" - ]} - """.trimIndent(), - ) - } - - @AfterEach - fun `clear referrals`() { - setupAssistant.cleanAll() - } -} diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/integration/authorization/RequestFactory.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/integration/authorization/RequestFactory.kt index 28ade1a0b..eeb331cff 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/integration/authorization/RequestFactory.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/integration/authorization/RequestFactory.kt @@ -21,7 +21,6 @@ enum class Request { EndSentReferral, GetDraftReferrals, GetSentReferralSummaries, - GetServiceProviderReferralsSummary, CreateCaseNote, } @@ -48,8 +47,6 @@ class RequestFactory(private val webTestClient: WebTestClient, private val setup Request.GetDraftReferrals -> webTestClient.get().uri("/draft-referrals") Request.GetSentReferralSummaries -> webTestClient.get().uri("/sent-referrals/summaries") - Request.GetServiceProviderReferralsSummary -> webTestClient.get().uri("/sent-referrals/summary/service-provider") - Request.CreateCaseNote -> webTestClient.post().uri("/case-note").bodyValue( if (body != null) body as CreateCaseNoteDTO else CreateCaseNoteDTO(urlParams[0] as UUID, "subject", "body", false), ) diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/jpa/repository/ReferralRepositoryTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/jpa/repository/ReferralRepositoryTest.kt deleted file mode 100644 index 2c12a5c91..000000000 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/jpa/repository/ReferralRepositoryTest.kt +++ /dev/null @@ -1,520 +0,0 @@ -package uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.repository - -import org.apache.commons.lang3.RandomStringUtils -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Nested -import org.junit.jupiter.api.Test -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager -import org.springframework.data.domain.PageRequest -import org.springframework.transaction.annotation.Transactional -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.dto.DashboardType -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Attended -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.AuthUser -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.DraftReferral -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Intervention -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Referral -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.ServiceProviderSentReferralSummary -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.util.ActionPlanFactory -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.util.AppointmentFactory -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.util.AssignmentsFactory -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.util.AuthUserFactory -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.util.DynamicFrameworkContractFactory -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.util.EndOfServiceReportFactory -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.util.InterventionFactory -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.util.ReferralFactory -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.util.RepositoryTest -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.util.ServiceProviderFactory -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.util.ServiceUserFactory -import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.util.SupplierAssessmentFactory -import java.time.OffsetDateTime - -@Transactional -@RepositoryTest -class ReferralRepositoryTest @Autowired constructor( - val entityManager: TestEntityManager, - val endOfServiceReportRepository: EndOfServiceReportRepository, - val referralRepository: ReferralRepository, - val interventionRepository: InterventionRepository, - val authUserRepository: AuthUserRepository, -) { - private val authUserFactory = AuthUserFactory(entityManager) - private val referralFactory = ReferralFactory(entityManager) - private val dynamicFrameworkContractFactory = DynamicFrameworkContractFactory(entityManager) - private val interventionFactory = InterventionFactory(entityManager) - private val serviceProviderFactory = ServiceProviderFactory(entityManager) - private val serviceUserFactory = ServiceUserFactory(entityManager) - private var endOfServiceReport = EndOfServiceReportFactory(entityManager) - private val actionPlanFactory = ActionPlanFactory(entityManager) - private val appointmentFactory = AppointmentFactory(entityManager) - private val supplierAssessmentFactory = SupplierAssessmentFactory(entityManager) - private val assignmentsFactory = AssignmentsFactory(entityManager) - - private lateinit var authUser: AuthUser - - @BeforeEach - fun beforeEach() { - authUser = authUserFactory.create() - } - - @Nested - inner class ServiceProviderSelection { - - @Test - fun `can obtain a single referral summary using prime provider`() { - val referralWithPrimeSp = createReferral(true) - val referralWithAnotherPrimeSp = createReferral(true) - - val serviceProviderSearchId = referralWithPrimeSp.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf(serviceProviderSearchId)) - - assertThat(summaries.size).isEqualTo(1) - assertThat(contains(summaries, expectedSummary(referralWithPrimeSp))) - } - - @Test - fun `can obtain a single referral summary using subcontractor provider`() { - val referralWithSubConSp = createReferral(false) - val referralWithAnotherSubConSp = createReferral(false) - - val serviceProviderSearchId = referralWithSubConSp.intervention.dynamicFrameworkContract.subcontractorProviders.firstOrNull()!!.id - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf(serviceProviderSearchId)) - - assertThat(summaries.size).isEqualTo(1) - assertThat(contains(summaries, expectedSummary(referralWithSubConSp))) - } - - @Test - fun `can obtain a multiple referral summaries as subcontractor and as prime provider`() { - val referralWithPrimeSp = createReferral(true) - val referralWithAnotherPrimeSp = createReferral(true) - val referralWithSubConSp = createReferral(false) - val referralWithAnotherSubConSp = createReferral(false) - - val serviceProviderSearchIds = listOf( - referralWithPrimeSp.intervention.dynamicFrameworkContract.primeProvider.id, - referralWithSubConSp.intervention.dynamicFrameworkContract.subcontractorProviders.firstOrNull()!!.id, - ) - val summaries = referralRepository.getSentReferralSummaries(authUser, serviceProviderSearchIds) - - assertThat(summaries.size).isEqualTo(2) - assertThat(contains(summaries, expectedSummary(referralWithPrimeSp))) - assertThat(contains(summaries, expectedSummary(referralWithSubConSp))) - } - - @Test - fun `cannot obtain a single referral summary when provider doesn't match`() { - val referralWithPrimeSp = createReferral(true) - val referralWithSubConSp = createReferral(false) - - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf("NON_EXISTENT_SP")) - - assertThat(summaries.size).isEqualTo(0) - } - } - - @Nested - inner class AssignedToReferralSelection { - @Test - fun `can determine assigned user when only one`() { - val referralWithSingleAssignee = createReferral(true, 1) - - val serviceProviderSearchId = referralWithSingleAssignee.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf(serviceProviderSearchId)) - - assertThat(summaries.size).isEqualTo(1) - assertThat(contains(summaries, expectedSummary(referralWithSingleAssignee))) - } - - @Test - fun `can determine latest assigned user when changed`() { - val referralWithChangedAssignee = createReferral(true, 2) - - val serviceProviderSearchId = referralWithChangedAssignee.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf(serviceProviderSearchId)) - - assertThat(summaries.size).isEqualTo(1) - assertThat(contains(summaries, expectedSummary(referralWithChangedAssignee))) - } - - @Test - fun `can obtain multiple referrals with latest assigned`() { - val referralWithChangedAssignee = createReferral(true, 2) - val referralWithMultipleChangedAssignee = createReferral(true, 10) - - val serviceProviderSearchIds = listOf( - referralWithChangedAssignee.intervention.dynamicFrameworkContract.primeProvider.id, - referralWithMultipleChangedAssignee.intervention.dynamicFrameworkContract.primeProvider.id, - ) - val summaries = referralRepository.getSentReferralSummaries(authUser, serviceProviderSearchIds) - - assertThat(summaries.size).isEqualTo(2) - assertThat(contains(summaries, expectedSummary(referralWithChangedAssignee))) - assertThat(contains(summaries, expectedSummary(referralWithMultipleChangedAssignee))) - summaries.contains(expectedSummary(referralWithChangedAssignee)) - } - - @Test - fun `will not exclude referral when not assigned`() { - val referralWithNoAssignee = createReferral(true, 0) - - val serviceProviderSearchId = referralWithNoAssignee.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf(serviceProviderSearchId)) - - assertThat(summaries.size).isEqualTo(1) - assertThat(summaries[0].assignedToUserName).isNull() - assertThat(contains(summaries, expectedSummary(referralWithNoAssignee))) - } - } - - @Nested - inner class StatusExclusion { - - @Nested - inner class CancelledReferrals { - @Test - fun `will exclude cancelled referrals which are assigned and have no SAA booked`() { - val cancelledReferral = createEndedReferral( - true, - endRequestedAt = OffsetDateTime.now(), - concludedAt = OffsetDateTime.now(), - hasEosr = false, - ) - - val serviceProviderSearchId = cancelledReferral.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf(serviceProviderSearchId)) - - assertThat(summaries.size).isEqualTo(0) - } - - @Test - fun `will exclude cancelled referrals which have their SAA booked but with no feedback`() { - val cancelledReferral = createEndedReferral( - true, - endRequestedAt = OffsetDateTime.now(), - concludedAt = OffsetDateTime.now(), - hasEosr = false, - ) - - val appointment = appointmentFactory.create(referral = cancelledReferral) - val supplierAssessment = supplierAssessmentFactory.create(referral = cancelledReferral, appointment = appointment) - cancelledReferral.supplierAssessment = supplierAssessment - entityManager.refresh(cancelledReferral) - - val serviceProviderSearchId = cancelledReferral.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf(serviceProviderSearchId)) - - assertThat(summaries.size).isEqualTo(0) - } - - @Test - fun `will exclude cancelled referrals which have their Action Plan created but not submitted`() { - val cancelledReferral = createEndedReferral( - true, - endRequestedAt = OffsetDateTime.now(), - concludedAt = OffsetDateTime.now(), - hasEosr = false, - ) - - actionPlanFactory.create(referral = cancelledReferral) - - val serviceProviderSearchId = cancelledReferral.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf(serviceProviderSearchId)) - - assertThat(summaries.size).isEqualTo(0) - } - - @Test - fun `will include cancelled referrals which are which have their SAA with feedback`() { - val cancelledReferral = createEndedReferral( - true, - endRequestedAt = OffsetDateTime.now(), - concludedAt = OffsetDateTime.now(), - hasEosr = false, - ) - - val appointment = appointmentFactory.create(referral = cancelledReferral, attendanceSubmittedAt = OffsetDateTime.now()) - val supplierAssessment = supplierAssessmentFactory.create(referral = cancelledReferral, appointment = appointment) - cancelledReferral.supplierAssessment = supplierAssessment - entityManager.refresh(cancelledReferral) - - val serviceProviderSearchId = cancelledReferral.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf(serviceProviderSearchId)) - - assertThat(summaries.size).isEqualTo(1) - } - - @Test - fun `will include cancelled referrals which are which have their Action Plan submitted`() { - val cancelledReferral = createEndedReferral( - true, - endRequestedAt = OffsetDateTime.now(), - concludedAt = OffsetDateTime.now(), - hasEosr = false, - ) - - actionPlanFactory.createSubmitted(referral = cancelledReferral) - - val serviceProviderSearchId = cancelledReferral.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf(serviceProviderSearchId)) - - assertThat(summaries.size).isEqualTo(1) - } - } - - @Test - fun `can obtain those requested to be ended and not concluded`() { - val referral = createEndedReferral( - true, - endRequestedAt = OffsetDateTime.now(), - concludedAt = null, - hasEosr = false, - ) - - val serviceProviderSearchId = referral.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf(serviceProviderSearchId)) - - assertThat(summaries.size).isEqualTo(1) - assertThat(contains(summaries, expectedSummary(referral))) - } - - @Test - fun `can obtain prematurely or completely ended referral`() { - val referral = createEndedReferral( - true, - endRequestedAt = null, - concludedAt = OffsetDateTime.now(), - hasEosr = true, - ) - - val serviceProviderSearchId = referral.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf(serviceProviderSearchId)) - - assertThat(summaries.size).isEqualTo(1) - assertThat(contains(summaries, expectedSummary(referral))) - } - - @Test - fun `will exclude referral if draft`() { - val referralWithNoAssignee = createDraftReferral(true) - - val serviceProviderSearchId = referralWithNoAssignee.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf(serviceProviderSearchId)) - - assertThat(summaries.size).isEqualTo(0) - } - } - - @Nested - inner class DashboardTypeSelection { - - @Test - fun `does not show referrals where the user has been historically assigned but no longer the active assignee`() { - val assignedReferral = createReferral(true, 2) - val oldAssignee = assignedReferral.assignments[0].assignedTo - val serviceProviderSearchId = assignedReferral.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(oldAssignee, listOf(serviceProviderSearchId), DashboardType.MyCases) - - assertThat(summaries.size).isEqualTo(0) - } - - @Test - fun `MyCases dashboard type should only return logged in user referrals`() { - val assignedReferral = createReferral(true, 1) - val assignedToSomeoneElse = createReferral(true, 1, assignedReferral.intervention) - val serviceProviderSearchId = assignedReferral.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(assignedReferral.currentAssignee!!, listOf(serviceProviderSearchId), DashboardType.MyCases) - - assertThat(summaries.size).isEqualTo(1) - assertThat(contains(summaries, expectedSummary(assignedReferral))) - } - - @Test - fun `OpenCases dashboard type should only return referrals that don't have an EOSR submitted`() { - val openReferral = createReferral(true, 1) - val endedReferral = createEndedReferral(true, OffsetDateTime.now(), OffsetDateTime.now(), true, openReferral.intervention) - val serviceProviderSearchId = openReferral.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf(serviceProviderSearchId), DashboardType.OpenCases) - - assertThat(summaries.size).isEqualTo(1) - assertThat(contains(summaries, expectedSummary(openReferral))) - } - - @Test - fun `UnassignedCases dashboard type should only return referrals that aren't assigned`() { - val openReferral = createReferral(true, 1) - val unassignedReferral = createReferral(true, 0, openReferral.intervention) - val serviceProviderSearchId = openReferral.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf(serviceProviderSearchId), DashboardType.UnassignedCases) - - assertThat(summaries.size).isEqualTo(1) - assertThat(contains(summaries, expectedSummary(unassignedReferral))) - } - - @Test - fun `CompletedCases dashboard type should only return referrals that have been concluded`() { - val openReferral = createReferral(true, 1) - val concludedReferral = createEndedReferral(true, OffsetDateTime.now(), OffsetDateTime.now(), true, openReferral.intervention) - val serviceProviderSearchId = openReferral.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf(serviceProviderSearchId), DashboardType.CompletedCases) - - assertThat(summaries.size).isEqualTo(1) - assertThat(contains(summaries, expectedSummary(concludedReferral))) - } - - @Test - fun `completed dashboard type should return cancelled referrals that have action plan submitted`() { - val openReferral = createReferral(true, 1) - val cancelledReferral = createEndedReferral(true, OffsetDateTime.now(), OffsetDateTime.now(), false, openReferral.intervention) - val cancelledReferralWithSubmittedActionPlan = createEndedReferral(true, OffsetDateTime.now(), OffsetDateTime.now(), false, openReferral.intervention) - actionPlanFactory.createSubmitted(referral = cancelledReferralWithSubmittedActionPlan) - val serviceProviderSearchId = openReferral.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf(serviceProviderSearchId), DashboardType.CompletedCases) - - assertThat(summaries.size).isEqualTo(1) - assertThat(contains(summaries, expectedSummary(cancelledReferralWithSubmittedActionPlan))) - } - - @Test - fun `completed dashboard type should return cancelled referrals that have an SAA attendance recorded plan submitted`() { - val openReferral = createReferral(true, 1) - val cancelledReferral = createEndedReferral(true, OffsetDateTime.now(), OffsetDateTime.now(), false, openReferral.intervention) - val cancelledReferralWithSaaAttended = createEndedReferral(true, OffsetDateTime.now(), OffsetDateTime.now(), false, openReferral.intervention) - val appointment = appointmentFactory.create(referral = cancelledReferralWithSaaAttended, attended = Attended.YES, attendanceSubmittedAt = OffsetDateTime.now()) - supplierAssessmentFactory.create(referral = cancelledReferralWithSaaAttended, appointment = appointment) - val serviceProviderSearchId = openReferral.intervention.dynamicFrameworkContract.primeProvider.id - val summaries = referralRepository.getSentReferralSummaries(authUser, listOf(serviceProviderSearchId), DashboardType.CompletedCases) - - assertThat(summaries.size).isEqualTo(1) - assertThat(contains(summaries, expectedSummary(cancelledReferralWithSaaAttended))) - } - } - - private fun createIntervention(asPrime: Boolean): Intervention { - val serviceProvider = serviceProviderFactory.create(random(13), random(14)) - val contract = when { - asPrime -> dynamicFrameworkContractFactory.create( - primeProvider = serviceProvider, - contractReference = random(10), - ) - else -> dynamicFrameworkContractFactory.create( - subcontractorProviders = mutableSetOf(serviceProvider), - contractReference = random(10), - ) - } - return interventionFactory.create(contract = contract) - } - - private fun createReferral( - asPrime: Boolean, - numberOfAssignedUsers: Int = 1, - intervention: Intervention? = null, - ): Referral { - val referral: Referral = referralFactory.createSent( - intervention = intervention ?: createIntervention(asPrime), - assignments = assignmentsFactory.create(numberOfAssignedUsers), - ) - - val draftReferral = entityManager.find(DraftReferral::class.java, referral.id) - val serviceUser = serviceUserFactory.create(random(15), random(16), draftReferral) - entityManager.refresh(draftReferral) - - return entityManager.refresh(referral) - } - - private fun createEndedReferral( - asPrime: Boolean, - endRequestedAt: OffsetDateTime? = null, - concludedAt: OffsetDateTime? = null, - hasEosr: Boolean = false, - intervention: Intervention? = null, - ): Referral { - val referral: Referral = intervention?.let { intervention -> - referralFactory.createEnded( - intervention = intervention, - assignments = assignmentsFactory.create(1), - endRequestedAt = endRequestedAt, - concludedAt = concludedAt, - ) - } ?: run { - referralFactory.createEnded( - intervention = createIntervention(asPrime), - assignments = assignmentsFactory.create(1), - endRequestedAt = endRequestedAt, - concludedAt = concludedAt, - ) - } - if (hasEosr) { - referral.endOfServiceReport = endOfServiceReport.create(referral = referral, submittedAt = OffsetDateTime.now()) - } - - val draftReferral = entityManager.find(DraftReferral::class.java, referral.id) - val serviceUser = serviceUserFactory.create(random(15), random(16), draftReferral) - entityManager.refresh(draftReferral) - return entityManager.refresh(referral) - } - - private fun createDraftReferral( - asPrime: Boolean, - ): DraftReferral { - val serviceProvider = serviceProviderFactory.create(random(13), random(14)) - val contract = when { - asPrime -> dynamicFrameworkContractFactory.create(primeProvider = serviceProvider, contractReference = random(10)) - else -> dynamicFrameworkContractFactory.create(subcontractorProviders = mutableSetOf(serviceProvider), contractReference = random(10)) - } - val intervention = interventionFactory.create(contract = contract) - val referral = referralFactory.createDraft(intervention = intervention) - val serviceUser = serviceUserFactory.create(random(15), random(16), referral) - - return entityManager.refresh(referral) - } - - private fun random(length: Int): String { - return RandomStringUtils.randomAlphabetic(length) - } - - private fun contains(summaries: List, summary: ServiceProviderSentReferralSummary): Boolean { - return summaries.any { - it.referralId == summary.referralId.toString() && - it.sentAt == summary.sentAt && - it.referenceNumber == summary.referenceNumber && - it.interventionTitle == summary.interventionTitle && - it.dynamicFrameWorkContractId == summary.dynamicFrameWorkContractId && - it.assignedToUserName == summary.assignedToUserName && - it.serviceUserFirstName == summary.serviceUserFirstName && - it.serviceUserLastName == summary.serviceUserLastName && - it.endOfServiceReportId == summary.endOfServiceReportId && - it.endOfServiceReportSubmittedAt == summary.endOfServiceReportSubmittedAt - } - } - - private fun expectedSummary(referral: Referral) = - ServiceProviderSentReferralSummary( - referral.id.toString(), - referral.sentAt!!.toInstant(), - referral.referenceNumber!!, - referral.intervention.title, - referral.intervention.dynamicFrameworkContract.id.toString(), - referral.currentAssignee?.id, - referral.serviceUserData!!.firstName, - referral.serviceUserData!!.lastName, - referral.endOfServiceReport?.id, - referral.endOfServiceReport?.submittedAt?.toInstant(), - ) - - @Test - fun `service provider report sanity check`() { - val referral = referralFactory.createSent() - referralFactory.createSent(sentAt = OffsetDateTime.now().minusHours(2), intervention = referral.intervention) - - val referrals = referralRepository.serviceProviderReportReferrals( - OffsetDateTime.now().minusHours(1), - OffsetDateTime.now().plusHours(1), - setOf(referral.intervention.dynamicFrameworkContract), - PageRequest.of(0, 5), - ) - - assertThat(referrals.numberOfElements).isEqualTo(1) - } -} diff --git a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/service/ReferralServiceTest.kt b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/service/ReferralServiceTest.kt index 088d3789a..6202e0929 100644 --- a/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/service/ReferralServiceTest.kt +++ b/src/test/kotlin/uk/gov/justice/digital/hmpps/hmppsinterventionsservice/service/ReferralServiceTest.kt @@ -413,208 +413,6 @@ class ReferralServiceTest @Autowired constructor( } } - @Nested - @DisplayName("get sent referrals summary with a service provider user") - inner class GetServiceProviderSummaries { - @Test - fun `user with multiple providers can see referrals where the providers are subcontractors`() { - val userProviders = listOf("test_org_1", "test_org_2", "test_org_3", "test_org_4", "test_org_5").map { id -> serviceProviderFactory.create(id = id, name = id) } - val contractWithUserProviderAsPrime = contractFactory.create(primeProvider = userProviders[0]) - val contractWithUserProviderAsSub1 = contractFactory.create(subcontractorProviders = mutableSetOf(userProviders[1])) - val contractWithUserProviderAsSub2 = contractFactory.create(subcontractorProviders = mutableSetOf(userProviders[2])) - val contractWithUserProviderAsBothPrimeAndSub = contractFactory.create(primeProvider = userProviders[3], subcontractorProviders = mutableSetOf(userProviders[4])) - val contractWithNoUserProviders = contractFactory.create() - - val primeRef = referralFactory.createSent(intervention = interventionFactory.create(contract = contractWithUserProviderAsPrime)) - val primeAndSubRef = referralFactory.createSent(intervention = interventionFactory.create(contract = contractWithUserProviderAsBothPrimeAndSub)) - val refWithAllProvidersBeingSubs = referralFactory.createSent(intervention = interventionFactory.create(contract = contractWithUserProviderAsSub1)) - val subRef = referralFactory.createSent(intervention = interventionFactory.create(contract = contractWithUserProviderAsSub2)) - val noAccess = referralFactory.createSent(intervention = interventionFactory.create(contract = contractWithNoUserProviders)) - - val user = userFactory.create("test_user", "auth") - whenever(serviceProviderAccessScopeMapper.fromUser(user)) - .thenReturn(ServiceProviderAccessScope(userProviders.toSet(), setOf(contractWithUserProviderAsBothPrimeAndSub, contractWithUserProviderAsPrime, contractWithUserProviderAsSub1, contractWithUserProviderAsSub2))) - - val result = referralService.getServiceProviderSummaries(user) - assertThat(result.size).isEqualTo(4) - val referralIds = result.map { summary -> UUID.fromString(summary.referralId) } - assertThat(referralIds).doesNotContain(noAccess.id) - assertThat(referralIds).containsAll( - listOf( - primeRef.id, - primeAndSubRef.id, - refWithAllProvidersBeingSubs.id, - subRef.id, - ), - ) - } - - @Test - fun `referrals that are sent, premature end requested or prematurely ended are returned`() { - val provider = serviceProviderFactory.create(id = "test") - val intervention = interventionFactory.create(contract = contractFactory.create(primeProvider = provider)) - - val refLive = referralFactory.createSent(intervention = intervention) - val refPrematureEnded = referralFactory.createEnded( - intervention = intervention, - endRequestedReason = cancellationReasonFactory.create("ANY"), - endRequestedAt = OffsetDateTime.now(), - concludedAt = OffsetDateTime.now(), - ).also { referral -> - referral.endOfServiceReport = endOfServiceReportFactory.create(referral = referral) - } - - val refPrematureEndRequested = referralFactory.createEnded( - intervention = intervention, - endRequestedReason = cancellationReasonFactory.create("ANY"), - endRequestedAt = OffsetDateTime.now(), - concludedAt = null, - ) - - val user = userFactory.create("test_user", "auth") - whenever(serviceProviderAccessScopeMapper.fromUser(user)) - .thenReturn(ServiceProviderAccessScope(setOf(provider), setOf(intervention.dynamicFrameworkContract))) - val result = referralService.getServiceProviderSummaries(user) - val referralIds = result.map { summary -> UUID.fromString(summary.referralId) } - assertThat(referralIds).containsExactlyInAnyOrder(refLive.id, refPrematureEnded.id, refPrematureEndRequested.id) - } - - @Test - fun `referrals that are cancelled with no SAA feedback are not returned`() { - val provider = serviceProviderFactory.create(id = "test") - val intervention = interventionFactory.create(contract = contractFactory.create(primeProvider = provider)) - - val refCancelled = referralFactory.createEnded( - intervention = intervention, - endRequestedReason = cancellationReasonFactory.create("ANY"), - concludedAt = OffsetDateTime.now(), - endOfServiceReport = null, - ) - - val appointment = appointmentFactory.create(referral = refCancelled) - val supplierAssessmentAppointment = - supplierAssessmentFactory.create(appointment = appointment, referral = refCancelled) - refCancelled.supplierAssessment = supplierAssessmentAppointment - entityManager.refresh(refCancelled) - - val user = userFactory.create("test_user", "auth") - whenever(serviceProviderAccessScopeMapper.fromUser(user)) - .thenReturn(ServiceProviderAccessScope(setOf(provider), setOf(intervention.dynamicFrameworkContract))) - val result = referralService.getServiceProviderSummaries(user) - val referralIds = result.map { summary -> UUID.fromString(summary.referralId) } - assertThat(referralIds).isEmpty() - } - - @Test - fun `referrals that are cancelled with SAA feedback are returned`() { - val provider = serviceProviderFactory.create(id = "test") - val intervention = interventionFactory.create(contract = contractFactory.create(primeProvider = provider)) - - val refCancelled = referralFactory.createEnded( - intervention = intervention, - endRequestedReason = cancellationReasonFactory.create("ANY"), - concludedAt = OffsetDateTime.now(), - endOfServiceReport = null, - ) - - val appointment = - appointmentFactory.create(referral = refCancelled, attendanceSubmittedAt = OffsetDateTime.now()) - val supplierAssessmentAppointment = - supplierAssessmentFactory.create(appointment = appointment, referral = refCancelled) - refCancelled.supplierAssessment = supplierAssessmentAppointment - entityManager.refresh(refCancelled) - - val user = userFactory.create("test_user", "auth") - whenever(serviceProviderAccessScopeMapper.fromUser(user)) - .thenReturn(ServiceProviderAccessScope(setOf(provider), setOf(intervention.dynamicFrameworkContract))) - val result = referralService.getServiceProviderSummaries(user) - val referralIds = result.map { summary -> UUID.fromString(summary.referralId) } - assertThat(referralIds).containsExactly(refCancelled.id) - } - - @Test - fun `referrals that are cancelled with Action Plan created but not submitted are not returned`() { - val provider = serviceProviderFactory.create(id = "test") - val intervention = interventionFactory.create(contract = contractFactory.create(primeProvider = provider)) - - val refCancelled = referralFactory.createEnded( - intervention = intervention, - endRequestedReason = cancellationReasonFactory.create("ANY"), - concludedAt = OffsetDateTime.now(), - endOfServiceReport = null, - ) - - actionPlanFactory.create(referral = refCancelled) - - val user = userFactory.create("test_user", "auth") - whenever(serviceProviderAccessScopeMapper.fromUser(user)) - .thenReturn(ServiceProviderAccessScope(setOf(provider), setOf(intervention.dynamicFrameworkContract))) - val result = referralService.getServiceProviderSummaries(user) - val referralIds = result.map { summary -> UUID.fromString(summary.referralId) } - assertThat(referralIds).isEmpty() - } - - @Test - fun `referrals that are cancelled with Action Plan submitted are returned`() { - val provider = serviceProviderFactory.create(id = "test") - val intervention = interventionFactory.create(contract = contractFactory.create(primeProvider = provider)) - - val refCancelled = referralFactory.createEnded( - intervention = intervention, - endRequestedReason = cancellationReasonFactory.create("ANY"), - concludedAt = OffsetDateTime.now(), - endOfServiceReport = null, - ) - - actionPlanFactory.createSubmitted(referral = refCancelled) - - val user = userFactory.create("test_user", "auth") - whenever(serviceProviderAccessScopeMapper.fromUser(user)) - .thenReturn(ServiceProviderAccessScope(setOf(provider), setOf(intervention.dynamicFrameworkContract))) - val result = referralService.getServiceProviderSummaries(user) - val referralIds = result.map { summary -> UUID.fromString(summary.referralId) } - assertThat(referralIds).containsExactly(refCancelled.id) - } - - @Test - fun `sent referral summary provides correct details for end of service report`() { - val provider = serviceProviderFactory.create(id = "test") - val contract = contractFactory.create(primeProvider = provider) - val intervention = interventionFactory.create(contract = contract) - - val refLive = referralFactory.createSent(intervention = intervention) - val endOfServiceReportCreated = referralFactory.createSent( - intervention = intervention, - ).also { referral -> - referral.endOfServiceReport = endOfServiceReportFactory.create(referral = referral) - } - val endOfServiceReportSubmitted = referralFactory.createEnded( - intervention = intervention, - endRequestedReason = cancellationReasonFactory.create("ANY"), - concludedAt = OffsetDateTime.now(), - ).also { referral -> - referral.endOfServiceReport = - endOfServiceReportFactory.create(referral = referral, submittedAt = OffsetDateTime.now()) - } - - val user = userFactory.create("test_user", "auth") - whenever(serviceProviderAccessScopeMapper.fromUser(user)) - .thenReturn(ServiceProviderAccessScope(setOf(provider), setOf(intervention.dynamicFrameworkContract))) - val result = referralService.getServiceProviderSummaries(user) - - val refLiveSummary = result.find { it.referralId == refLive.id.toString() } - assertThat(refLiveSummary!!.endOfServiceReportId).isNull() - assertThat(refLiveSummary!!.endOfServiceReportSubmittedAt).isNull() - val endOfServiceReportCreatedSummary = result.find { it.referralId == endOfServiceReportCreated.id.toString() } - assertThat(endOfServiceReportCreatedSummary!!.endOfServiceReportId).isNotNull() - assertThat(endOfServiceReportCreatedSummary!!.endOfServiceReportSubmittedAt).isNull() - val endOfServiceReportSubmittedSummary = - result.find { it.referralId == endOfServiceReportSubmitted.id.toString() } - assertThat(endOfServiceReportSubmittedSummary!!.endOfServiceReportId).isNotNull() - assertThat(endOfServiceReportSubmittedSummary!!.endOfServiceReportSubmittedAt).isNotNull() - } - } - @Nested @DisplayName("get sent referrals with person on probation search") inner class GetSentReferralsWithPopSearchTest {