Skip to content

Commit

Permalink
Decommissioning the deprecated getServiceProviderSentReferralsSummary…
Browse files Browse the repository at this point in the history
… API
  • Loading branch information
kth13 committed Sep 12, 2024
1 parent 5588ee4 commit 7c052b9
Show file tree
Hide file tree
Showing 9 changed files with 0 additions and 1,183 deletions.
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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<ServiceProviderSentReferralSummaryDTO> {
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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String>, dashboardType: DashboardType? = null): List<ServiceProviderSentReferralSummary>
fun getReferralSummaries(referralSummaryQuery: ReferralSummaryQuery): Page<ReferralSummary>
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,15 @@ 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
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,
Expand Down Expand Up @@ -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 """
Expand Down Expand Up @@ -204,30 +150,6 @@ WHERE assigned_at_desc_seq = 1
""".trimIndent()
}

override fun getSentReferralSummaries(authUser: AuthUser, serviceProviders: List<String>, dashboardType: DashboardType?): List<ServiceProviderSentReferralSummary> {
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<Array<Any>>
val summaries: MutableList<ServiceProviderSentReferralSummary> = 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<ReferralSummary> {
Expand Down Expand Up @@ -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())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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<ServiceProviderSentReferralSummary> {
if (userTypeChecker.isServiceProviderUser(user)) {
return getSentReferralSummariesForServiceProviderUser(user, dashboardType)
}
throw AccessError(user, "unsupported user type", listOf("logins from ${user.authSource} are not supported"))
}

private fun <T> applyOptionalConjunction(existingSpec: Specification<T>, predicate: Boolean?, specToJoin: Specification<T>): Specification<T> {
if (predicate == null) return existingSpec
return existingSpec.and(if (predicate) specToJoin else not(specToJoin))
}

private fun getSentReferralSummariesForServiceProviderUser(user: AuthUser, dashboardType: DashboardType?): List<ServiceProviderSentReferralSummary> {
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 <reified T> createSpecification(
concluded: Boolean?,
cancelled: Boolean?,
unassigned: Boolean?,
assignedToUserId: String?,
searchText: String?,
): Specification<T> {
var findSentReferralsSpec = ReferralSpecifications.sent<T>()

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 <T> searchSpec(searchText: String): Specification<T> {
return if (searchText.matches(Regex("[A-Z]{2}[0-9]{4}[A-Z]{2}"))) {
ReferralSpecifications.searchByReferenceNumber(searchText)
} else {
ReferralSpecifications.searchByPoPName(searchText)
}
}

private fun <T> createSpecificationForProbationPractitionerUser(
user: AuthUser,
sentReferralFilterSpecification: Specification<T>,
): Specification<T> {
var referralsForPPUser = ReferralSpecifications.createdBy<T>(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<String> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<IllegalArgumentException> {
referralController.getServiceProviderSentReferralsSummary(
token,
"invalidDashBoardType",
)
}
}
}

@Test
fun `assignSentReferral returns 404 if referral does not exist`() {
whenever(referralService.getSentReferralForUser(any(), any())).thenReturn(null)
Expand Down
Loading

0 comments on commit 7c052b9

Please sign in to comment.