Skip to content

Commit

Permalink
Add referral status (#1995)
Browse files Browse the repository at this point in the history
* Add referral status

* Add referral status index
  • Loading branch information
marcocolluramoj authored Aug 13, 2024
1 parent db2b87e commit 8fdc37d
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.dto.DeliverySessio
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.dto.DeliverySessionDTO
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.dto.SessionFeedbackRequestDTO
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.dto.UpdateAppointmentDTO
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Attended
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Status
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.service.ActionPlanService
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.service.AppointmentService
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.service.DeliverySessionService
Expand Down Expand Up @@ -79,6 +81,12 @@ class DeliverySessionController(
updateAppointmentDTO.sessionFeedback?.sessionBehaviour,
updateAppointmentDTO.sessionFeedback?.sessionConcerns,
)
if (updateAppointmentDTO.attendanceFeedback?.attended != Attended.NO) {
val referral = session.currentAppointment?.referral ?: session.referral
if (referral.status != Status.POST_ICA) {
referralService.setReferralStatus(referral, Status.POST_ICA)
}
}
return DeliverySessionDTO.from(deliverySession)
}

Expand Down Expand Up @@ -304,6 +312,11 @@ class DeliverySessionController(
)
referralAccessChecker.forUser(referral, user)
val sessionAndAppointment = deliverySessionService.submitAppointmentFeedback(referralId, appointmentId, user)
if (sessionAndAppointment.second.attended != Attended.NO) {
if (referral.status != Status.POST_ICA) {
referralService.setReferralStatus(referral, Status.POST_ICA)
}
}
return DeliverySessionAppointmentDTO.from(sessionAndAppointment.first.sessionNumber, sessionAndAppointment.second)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ class ReferralController(
fun getSentReferralsSummaries(
authentication: JwtAuthenticationToken,
@Nullable
@RequestParam(name = "concluded", required = false)
concluded: Boolean?,
@RequestParam(name = "completed", required = false)
completed: Boolean?,
@Nullable
@RequestParam(name = "cancelled", required = false)
cancelled: Boolean?,
Expand All @@ -109,7 +109,7 @@ class ReferralController(
@PageableDefault(page = 0, size = 50, sort = ["sentAt"]) page: Pageable,
): Page<SentReferralSummariesDTO> {
val user = userMapper.fromToken(authentication)
return (referralService.getSentReferralSummaryForUser(user, concluded, cancelled, unassigned, assignedToUserId, page, searchText) as Page<ReferralSummary>).map { SentReferralSummariesDTO.from(it) }.also {
return (referralService.getSentReferralSummaryForUser(user, completed, cancelled, unassigned, assignedToUserId, page, searchText) as Page<ReferralSummary>).map { SentReferralSummariesDTO.from(it) }.also {
telemetryClient.trackEvent(
"PagedDashboardRequest",
null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import jakarta.persistence.Column
import jakarta.persistence.ElementCollection
import jakarta.persistence.Embeddable
import jakarta.persistence.Entity
import jakarta.persistence.EnumType
import jakarta.persistence.Enumerated
import jakarta.persistence.FetchType
import jakarta.persistence.Id
import jakarta.persistence.Index
Expand All @@ -22,6 +24,8 @@ import jakarta.persistence.Table
import jakarta.validation.constraints.NotNull
import org.hibernate.annotations.Fetch
import org.hibernate.annotations.FetchMode.JOIN
import org.hibernate.annotations.JdbcType
import org.hibernate.dialect.PostgreSQLEnumJdbcType
import java.time.LocalDate
import java.time.OffsetDateTime
import java.util.UUID
Expand All @@ -34,6 +38,11 @@ class SelectedDesiredOutcomesMapping(
var desiredOutcomeId: UUID,
)

enum class Status {
PRE_ICA,
POST_ICA,
}

@Entity
@Table(name = "referral", indexes = [Index(columnList = "created_by_id")])
class Referral(
Expand Down Expand Up @@ -125,6 +134,12 @@ class Referral(

@Column(name = "withdrawal_reason_code") var withdrawalReasonCode: String? = null,
@Column(name = "withdrawal_comments") var withdrawalComments: String? = null,

@Enumerated(EnumType.STRING)
@Column(columnDefinition = "status")
@JdbcType(PostgreSQLEnumJdbcType::class)
@org.jetbrains.annotations.NotNull
var status: Status? = Status.PRE_ICA,
) {
val urn: String
get() = "urn:hmpps:interventions-referral:$id"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ WHERE assigned_at_desc_seq = 1
referralSummaryQuery: ReferralSummaryQuery,
): Page<ReferralSummary> {
val (
concluded,
completed,
cancelled,
unassigned,
assignedToUserId,
Expand All @@ -245,7 +245,7 @@ WHERE assigned_at_desc_seq = 1
contracts,
) = referralSummaryQuery

val queryBuilder = StringBuilder(referralSummaryQuery(constructCustomCriteria(concluded, cancelled, unassigned, assignedToUserId, searchText, isSpUser, isPPUser, contracts)))
val queryBuilder = StringBuilder(referralSummaryQuery(constructCustomCriteria(completed, cancelled, unassigned, assignedToUserId, searchText, isSpUser, isPPUser, contracts)))

// Append ORDER BY clause if sorting is specified
if (page.sort.isSorted) {
Expand Down Expand Up @@ -354,7 +354,7 @@ WHERE assigned_at_desc_seq = 1
}

val totalCount = totalCount(
concluded,
completed,
cancelled,
unassigned,
assignedToUserId,
Expand All @@ -373,7 +373,7 @@ WHERE assigned_at_desc_seq = 1
}

private fun totalCount(
concluded: Boolean?,
completed: Boolean?,
cancelled: Boolean?,
unassigned: Boolean?,
assignedToUserId: String?,
Expand All @@ -388,7 +388,7 @@ WHERE assigned_at_desc_seq = 1
val countQuery = "SELECT COUNT(*) FROM (${
referralSummaryQuery(
constructCustomCriteria(
concluded,
completed,
cancelled,
unassigned,
assignedToUserId,
Expand Down Expand Up @@ -431,7 +431,7 @@ WHERE assigned_at_desc_seq = 1
}

private fun constructCustomCriteria(
concluded: Boolean?,
completed: Boolean?,
cancelled: Boolean?,
unassigned: Boolean?,
assignedToUserId: String?,
Expand All @@ -441,8 +441,8 @@ WHERE assigned_at_desc_seq = 1
contracts: Set<DynamicFrameworkContract>,
): String {
val customCriteria = StringBuilder()
concluded?.let { if (it) customCriteria.append("and r.concluded_at is not null ") else customCriteria.append("and r.concluded_at is null ") }
cancelled?.let { if (it) customCriteria.append("and (r.concluded_at is not null and r.end_requested_at is not null and eosr.id is null) ") else customCriteria.append("and not (r.concluded_at is not null and r.end_requested_at is not null and eosr.id is null) ") }
completed?.let { if (it) customCriteria.append("and (r.concluded_at is not null and eosr.id is not null and r.status = 'POST_ICA')") else customCriteria.append("and not(r.concluded_at is not null and eosr.id is not null and r.status = 'POST_ICA')") }
cancelled?.let { if (it) customCriteria.append("and (r.concluded_at is not null and r.end_requested_at is not null and eosr.id is null and r.status = 'PRE_ICA') ") else customCriteria.append("and not (r.concluded_at is not null and r.end_requested_at is not null and eosr.id is null and r.status = 'PRE_ICA') ") }
unassigned?.let { if (it) customCriteria.append("and ra.assigned_to_id is null ") else customCriteria.append("and not (ra.assigned_to_id is null) ") }
assignedToUserId?.let { customCriteria.append("and au.id = :assignedToUserId ") }
searchText?.let { customCriteria.append(searchQuery(it)) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Referra
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
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.repository.CancellationReasonRepository
Expand All @@ -55,7 +56,7 @@ data class ResponsibleProbationPractitioner(
) : ContactablePerson

data class ReferralSummaryQuery(
val concluded: Boolean?,
val completed: Boolean?,
val cancelled: Boolean?,
val unassigned: Boolean?,
val assignedToUserId: String?,
Expand Down Expand Up @@ -130,11 +131,16 @@ class ReferralService(
return assignedReferral
}

fun getSentReferralSummaryForUser(user: AuthUser, concluded: Boolean?, cancelled: Boolean?, unassigned: Boolean?, assignedToUserId: String?, page: Pageable, searchText: String? = null): Iterable<ReferralSummary> {
fun setReferralStatus(referral: Referral, status: Status) {
referral.status = status
referralRepository.save(referral)
}

fun getSentReferralSummaryForUser(user: AuthUser, completed: Boolean?, cancelled: Boolean?, unassigned: Boolean?, assignedToUserId: String?, page: Pageable, searchText: String? = null): Iterable<ReferralSummary> {
if (userTypeChecker.isServiceProviderUser(user)) {
val contracts = serviceProviderUserAccessScopeMapper.fromUser(user).contracts
val referralSummary = ReferralSummaryQuery(
concluded,
completed,
cancelled,
unassigned,
assignedToUserId,
Expand All @@ -151,7 +157,7 @@ class ReferralService(
if (userTypeChecker.isProbationPractitionerUser(user)) {
val serviceUserCrns = crnsAssociatedWithPP(user)
val referralSummary = ReferralSummaryQuery(
concluded,
completed,
cancelled,
unassigned,
assignedToUserId,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CREATE TYPE status AS ENUM ('PRE_ICA','POST_ICA');

alter table referral
add column status status;

create index idx_referral_status on referral (status);

INSERT INTO metadata (table_name, column_name, sensitive, domain_data) VALUES ('referral','status', FALSE, TRUE);
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import org.springframework.web.server.ResponseStatusException
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.authorization.ReferralAccessChecker
Expand All @@ -22,6 +24,7 @@ import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Appoint
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.AppointmentSessionType
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Attended.NO
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Attended.YES
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Status
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.repository.AuthUserRepository
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.service.ActionPlanService
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.service.AppointmentService
Expand Down Expand Up @@ -194,6 +197,86 @@ internal class DeliverySessionControllerTest {

assertThat(sessionResponse).isEqualTo(DeliverySessionDTO.from(deliverySession))
}

@Test
fun `updates a session and sets referral status to post ica when the session was attended`() {
val user = authUserFactory.create()
val userToken = jwtTokenFactory.create(user)
val deliverySession = deliverySessionFactory.createScheduled(createdBy = user)
val actionPlanId = UUID.randomUUID()
val sessionNumber = deliverySession.sessionNumber

val attendanceFeedbackRequestDTO = AttendanceFeedbackRequestDTO(attended = YES, didSessionHappen = false)
val updateAppointmentDTO = UpdateAppointmentDTO(OffsetDateTime.now(), 10, AppointmentDeliveryType.PHONE_CALL, AppointmentSessionType.ONE_TO_ONE, null, null, attendanceFeedbackRequestDTO)

whenever(authUserRepository.save(any())).thenReturn(authUserFactory.create())
whenever(
sessionsService.getDeliverySessionByActionPlanIdOrThrowException(
actionPlanId,
sessionNumber,
),
).thenReturn(deliverySession)

whenever(
sessionsService.updateSessionAppointment(
actionPlanId,
sessionNumber,
updateAppointmentDTO.appointmentTime,
updateAppointmentDTO.durationInMinutes,
user,
AppointmentDeliveryType.PHONE_CALL,
AppointmentSessionType.ONE_TO_ONE,
attended = YES,
didSessionHappen = false,
),
).thenReturn(deliverySession)

val sessionResponse = sessionsController.updateSessionAppointment(actionPlanId, sessionNumber, updateAppointmentDTO, userToken)

verify(referralService, times(1)).setReferralStatus(deliverySession.currentAppointment!!.referral, Status.POST_ICA)

assertThat(sessionResponse).isEqualTo(DeliverySessionDTO.from(deliverySession))
}

@Test
fun `updates a session and does not set referral status to post ica when the session was not attended`() {
val user = authUserFactory.create()
val userToken = jwtTokenFactory.create(user)
val deliverySession = deliverySessionFactory.createScheduled(createdBy = user)
val actionPlanId = UUID.randomUUID()
val sessionNumber = deliverySession.sessionNumber

val attendanceFeedbackRequestDTO = AttendanceFeedbackRequestDTO(attended = NO, didSessionHappen = false)
val updateAppointmentDTO = UpdateAppointmentDTO(OffsetDateTime.now(), 10, AppointmentDeliveryType.PHONE_CALL, AppointmentSessionType.ONE_TO_ONE, null, null, attendanceFeedbackRequestDTO)

whenever(authUserRepository.save(any())).thenReturn(authUserFactory.create())
whenever(
sessionsService.getDeliverySessionByActionPlanIdOrThrowException(
actionPlanId,
sessionNumber,
),
).thenReturn(deliverySession)

whenever(
sessionsService.updateSessionAppointment(
actionPlanId,
sessionNumber,
updateAppointmentDTO.appointmentTime,
updateAppointmentDTO.durationInMinutes,
user,
AppointmentDeliveryType.PHONE_CALL,
AppointmentSessionType.ONE_TO_ONE,
attended = NO,
didSessionHappen = false,
),
).thenReturn(deliverySession)

val sessionResponse = sessionsController.updateSessionAppointment(actionPlanId, sessionNumber, updateAppointmentDTO, userToken)

verify(referralService, times(0)).setReferralStatus(deliverySession.currentAppointment!!.referral, Status.POST_ICA)

assertThat(sessionResponse).isEqualTo(DeliverySessionDTO.from(deliverySession))
}
}

@Nested
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Referra
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.ReferralAssignment
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.SentReferralSummary
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.ServiceProvider
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.entity.Status
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.repository.ActionPlanRepository
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.repository.AuthUserRepository
import uk.gov.justice.digital.hmpps.hmppsinterventionsservice.jpa.repository.CancellationReasonRepository
Expand Down Expand Up @@ -804,6 +805,7 @@ class ReferralServiceTest @Autowired constructor(
endRequestedReason = cancellationReasonFactory.create("ANY"),
endRequestedAt = OffsetDateTime.now(),
concludedAt = OffsetDateTime.now(),
status = Status.POST_ICA,
).also { referral ->
referral.endOfServiceReport = endOfServiceReportFactory.create(referral = referral)
}
Expand All @@ -823,6 +825,7 @@ class ReferralServiceTest @Autowired constructor(
concludedAt = OffsetDateTime.now(),
endOfServiceReport = null,
actionPlans = mutableListOf(actionPlanFactory.createSubmitted()),
status = Status.PRE_ICA,
)

cancelledSentReferralSummary = referralSummariesFactory.getReferralSummary(cancelledReferral)
Expand Down Expand Up @@ -868,7 +871,7 @@ class ReferralServiceTest @Autowired constructor(
}

@Test
fun `setting concluded returns only concluded referrals`() {
fun `setting completed returns only completed referrals`() {
val appointment =
appointmentFactory.create(referral = completedReferral, attendanceSubmittedAt = OffsetDateTime.now())
val superSededAppointment =
Expand All @@ -881,17 +884,17 @@ class ReferralServiceTest @Autowired constructor(
val result = referralService.getSentReferralSummaryForUser(user, true, null, null, null, pageRequest)
assertThat(result)
.usingRecursiveFieldByFieldElementComparator(recursiveComparisonConfiguration)
.containsExactlyInAnyOrder(completedSentReferralSummary, cancelledSentReferralSummary)
.containsExactlyInAnyOrder(completedSentReferralSummary)
assertThat(result).doesNotContain(liveSentReferralSummary, selfAssignedSentReferralSummary, otherAssignedSentReferralSummary)
}

@Test
fun `setting not concluded returns only non concluded referrals`() {
fun `setting not completed returns only non completed referrals`() {
val result = referralService.getSentReferralSummaryForUser(user, false, null, null, null, pageRequest)
assertThat(result)
.usingRecursiveFieldByFieldElementComparator(recursiveComparisonConfiguration)
.containsExactlyInAnyOrder(liveSentReferralSummary, selfAssignedSentReferralSummary, otherAssignedSentReferralSummary)
assertThat(result).doesNotContain(completedSentReferralSummary, cancelledSentReferralSummary)
.containsExactlyInAnyOrder(liveSentReferralSummary, selfAssignedSentReferralSummary, otherAssignedSentReferralSummary, cancelledSentReferralSummary)
assertThat(result).doesNotContain(completedSentReferralSummary)
}

@Test
Expand Down Expand Up @@ -981,7 +984,7 @@ class ReferralServiceTest @Autowired constructor(
entityManager.refresh(completedReferral)
completedSentReferralSummary = referralSummariesFactory.getReferralSummary(completedReferral)
val result = referralService.getSentReferralSummaryForUser(user, true, true, true, null, pageRequest)
assertThat(result).isNotEmpty
assertThat(result).isEmpty()
}

@Test
Expand Down
Loading

0 comments on commit 8fdc37d

Please sign in to comment.