From b384993d0eb7a46c94ecccbd44eef7d010b7ed06 Mon Sep 17 00:00:00 2001 From: Paul McPhee Date: Thu, 21 Mar 2024 19:18:20 +0000 Subject: [PATCH] PI-1991: Added schedule endpoints --- .../justice/digital/hmpps/data/DataLoader.kt | 11 + .../hmpps/data/generator/ContactGenerator.kt | 132 +++++++++- .../hmpps/data/generator/PersonGenerator.kt | 7 +- .../personalDetails/PersonDetailsGenerator.kt | 9 +- .../digital/hmpps/ScheduleIntegrationTest.kt | 84 ++++++ .../api/controller/ScheduleController.kt | 30 +++ .../hmpps/api/model/overview/Overview.kt | 2 + .../hmpps/api/model/schedule/Appointment.kt | 35 +++ .../hmpps/api/model/schedule/OfficeAddress.kt | 48 ++++ .../api/model/schedule/PersonAppointment.kt | 8 + .../hmpps/api/model/schedule/Schedule.kt | 8 + .../delius/overview/entity/Contact.kt | 244 +++++++++++++++++- .../delius/overview/entity/Requirement.kt | 1 + .../delius/personalDetails/entity/Document.kt | 5 + .../digital/hmpps/service/OverviewService.kt | 8 +- .../digital/hmpps/service/ScheduleService.kt | 96 +++++++ .../api/controller/ScheduleControllerTest.kt | 83 ++++++ .../hmpps/service/OverviewServiceTest.kt | 2 +- .../service/PersonalDetailsServiceTest.kt | 12 +- .../hmpps/service/ScheduleServiceTest.kt | 88 +++++++ .../justice/digital/hmpps/utils/Summary.kt | 15 ++ 21 files changed, 888 insertions(+), 40 deletions(-) create mode 100644 projects/manage-supervision-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/ScheduleIntegrationTest.kt create mode 100644 projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/controller/ScheduleController.kt create mode 100644 projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/schedule/Appointment.kt create mode 100644 projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/schedule/OfficeAddress.kt create mode 100644 projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/schedule/PersonAppointment.kt create mode 100644 projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/schedule/Schedule.kt create mode 100644 projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/ScheduleService.kt create mode 100644 projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/api/controller/ScheduleControllerTest.kt create mode 100644 projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ScheduleServiceTest.kt create mode 100644 projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/utils/Summary.kt diff --git a/projects/manage-supervision-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt b/projects/manage-supervision-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt index 788c821cf7..3eea849d87 100644 --- a/projects/manage-supervision-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt +++ b/projects/manage-supervision-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt @@ -26,6 +26,14 @@ class DataLoader( @Transactional override fun onApplicationEvent(are: ApplicationReadyEvent) { + entityManager.persistAll( + ContactGenerator.DEFAULT_PROVIDER, + ContactGenerator.DEFAULT_BOROUGH, + ContactGenerator.DEFAULT_DISTRICT, + ContactGenerator.DEFAULT_STAFF, + ContactGenerator.LOCATION_BRK_1 + ) + entityManager.persist(PersonGenerator.OVERVIEW.gender) entityManager.persist(UserGenerator.USER) PersonGenerator.DISABILITIES.forEach { entityManager.persist(it.type) } @@ -73,6 +81,9 @@ class DataLoader( ContactGenerator.FIRST_NON_APPT_CONTACT, ContactGenerator.NEXT_APPT_CONTACT, ContactGenerator.FIRST_APPT_CONTACT, + ContactGenerator.PREVIOUS_APPT_CONTACT_ABSENT, + ContactGenerator.CONTACT_DOCUMENT_1, + ContactGenerator.CONTACT_DOCUMENT_2, PersonGenerator.OFFENCE_1, PersonGenerator.MAIN_OFFENCE_1, PersonGenerator.OFFENCE_2, diff --git a/projects/manage-supervision-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ContactGenerator.kt b/projects/manage-supervision-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ContactGenerator.kt index efa5dd3172..9ad5dc89a5 100644 --- a/projects/manage-supervision-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ContactGenerator.kt +++ b/projects/manage-supervision-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/ContactGenerator.kt @@ -1,9 +1,11 @@ package uk.gov.justice.digital.hmpps.data.generator +import uk.gov.justice.digital.hmpps.data.generator.ContactGenerator.DEFAULT_BOROUGH +import uk.gov.justice.digital.hmpps.data.generator.ContactGenerator.DEFAULT_PROVIDER import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator.OVERVIEW -import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.Contact -import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.ContactType -import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.Person +import uk.gov.justice.digital.hmpps.data.generator.UserGenerator.USER +import uk.gov.justice.digital.hmpps.data.generator.personalDetails.PersonDetailsGenerator +import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.* import java.time.LocalDate import java.time.LocalDateTime import java.time.ZoneId @@ -11,11 +13,32 @@ import java.time.ZonedDateTime object ContactGenerator { + val DEFAULT_PROVIDER = generateProvider("N01") + val DEFAULT_BOROUGH = generateBorough("N01B") + val DEFAULT_DISTRICT = generateDistrict("N01D") + val LOCATION_BRK_1 = generateOfficeLocation( + code = "TVP_BRK", + description = "Bracknell Office", + buildingNumber = "21", + streetName = "Some Place", + district = "District 1", + town = "Hearth", + postcode = "H34 7TH", + ldu = DEFAULT_DISTRICT + ) + val DEFAULT_STAFF = generateStaff("N01BDT1", "John", "Smith") + val APPT_CT_1 = generateContactType("C089", true, "Alcohol Key Worker Session (NS)") val OTHER_CT = generateContactType("XXXX", false, "Non attendance contact type") val APPT_CT_2 = generateContactType("CODI", true, "Initial Appointment on Doorstep (NS)") val APPT_CT_3 = generateContactType("CODC", true, "Planned Doorstep Contact (NS)") + val PREVIOUS_APPT_CONTACT_ABSENT = generateContact( + OVERVIEW, + APPT_CT_1, + ZonedDateTime.of(LocalDateTime.now().minusDays(1), ZoneId.of("Europe/London")), + attended = false + ) val PREVIOUS_APPT_CONTACT = generateContact( OVERVIEW, APPT_CT_1, @@ -34,7 +57,24 @@ object ContactGenerator { val NEXT_APPT_CONTACT = generateContact( OVERVIEW, APPT_CT_3, - ZonedDateTime.of(LocalDateTime.now().plusHours(3), ZoneId.of("Europe/London")) + ZonedDateTime.of(LocalDateTime.now().plusHours(3), ZoneId.of("Europe/London")), + linkedDocumentContactId = IdGenerator.getAndIncrement() + ) + + val CONTACT_DOCUMENT_1 = PersonDetailsGenerator.generateDocument( + OVERVIEW.id, + "B001", + "contact.doc", + "DOCUMENT", + primaryKeyId = NEXT_APPT_CONTACT.linkedDocumentContactId + + ) + val CONTACT_DOCUMENT_2 = PersonDetailsGenerator.generateDocument( + OVERVIEW.id, + "B002", + "contact2.doc", + "DOCUMENT", + primaryKeyId = NEXT_APPT_CONTACT.linkedDocumentContactId ) fun generateContact( @@ -44,20 +84,84 @@ object ContactGenerator { rarActivity: Boolean? = null, attended: Boolean? = null, complied: Boolean? = null, - requirementId: Long? = null + sensitive: Boolean? = null, + requirement: Requirement? = null, + notes: String? = null, + linkedDocumentContactId: Long? = null ) = Contact( - IdGenerator.getAndIncrement(), - person.id, - contactType, - startDateTime.toLocalDate(), - ZonedDateTime.of(LocalDate.EPOCH, startDateTime.toLocalTime(), startDateTime.zone), - rarActivity, - attended, - complied, - requirementId + id = IdGenerator.getAndIncrement(), + personId = person.id, + type = contactType, + date = startDateTime.toLocalDate(), + startTime = ZonedDateTime.of(LocalDate.EPOCH, startDateTime.toLocalTime(), startDateTime.zone), + rarActivity = rarActivity, + attended = attended, + sensitive = sensitive, + complied = complied, + requirement = requirement, + lastUpdated = ZonedDateTime.now().minusDays(1), + lastUpdatedUser = USER, + staff = DEFAULT_STAFF, + location = LOCATION_BRK_1, + notes = notes, + linkedDocumentContactId = linkedDocumentContactId ) private fun generateContactType(code: String, attendance: Boolean, description: String) = ContactType(IdGenerator.getAndIncrement(), code, attendance, description) + + fun generateOfficeLocation( + code: String, + description: String, + buildingName: String? = null, + buildingNumber: String? = null, + streetName: String? = null, + district: String? = null, + town: String? = null, + county: String? = null, + postcode: String? = null, + telephoneNumber: String? = null, + startDate: LocalDate = LocalDate.now(), + endDate: LocalDate? = null, + ldu: District, + id: Long = IdGenerator.getAndIncrement() + ) = OfficeLocation( + code, + description, + buildingName, + buildingNumber, + streetName, + district, + town, + county, + postcode, + telephoneNumber, + startDate, + endDate, + ldu, + id + ) } +fun generateBorough( + code: String, + description: String = "Description of $code", + id: Long = IdGenerator.getAndIncrement(), +) = Borough(code, description, id) + +fun generateDistrict( + code: String, + description: String = "Description of $code", + borough: Borough = DEFAULT_BOROUGH, + id: Long = IdGenerator.getAndIncrement() +) = District(code, description, borough, id) + +fun generateProvider( + code: String, + description: String = "Description of $code", + id: Long = IdGenerator.getAndIncrement(), + endDate: LocalDate? = null +) = Provider(code, description, id, endDate) + +fun generateStaff(code: String, forename: String, surname: String, id: Long = IdGenerator.getAndIncrement()) = + Staff(code, forename, surname, DEFAULT_PROVIDER, id) \ No newline at end of file diff --git a/projects/manage-supervision-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt b/projects/manage-supervision-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt index 904ca33f2d..99f0d5ebda 100644 --- a/projects/manage-supervision-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt +++ b/projects/manage-supervision-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt @@ -4,7 +4,6 @@ import uk.gov.justice.digital.hmpps.data.generator.UserGenerator.USER import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.* import uk.gov.justice.digital.hmpps.integrations.delius.referencedata.entity.ReferenceData import uk.gov.justice.digital.hmpps.integrations.delius.sentence.entity.Court -import uk.gov.justice.digital.hmpps.integrations.delius.sentence.entity.CourtAppearance import java.time.LocalDate import java.time.LocalDateTime import java.time.ZoneId @@ -84,7 +83,7 @@ object PersonGenerator { LocalDate.now() ) - val MAIN_CAT_F = RequirementMainCategory(IdGenerator.getAndIncrement(), "F") + val MAIN_CAT_F = RequirementMainCategory(IdGenerator.getAndIncrement(), "F", "Main") val REQUIREMENT = generateRequirement(ACTIVE_ORDER) val REQUIREMENT_CONTACT_1 = ContactGenerator.generateContact( OVERVIEW, @@ -93,7 +92,7 @@ object PersonGenerator { rarActivity = true, attended = true, complied = true, - requirementId = REQUIREMENT.id + requirement = REQUIREMENT ) val REQUIREMENT_CONTACT_2 = ContactGenerator.generateContact( OVERVIEW, @@ -102,7 +101,7 @@ object PersonGenerator { rarActivity = true, attended = null, complied = true, - requirementId = REQUIREMENT.id + requirement = REQUIREMENT ) val REGISTER_TYPE_1 = generateRegisterType("CODE1", "Restraining Order") diff --git a/projects/manage-supervision-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/personalDetails/PersonDetailsGenerator.kt b/projects/manage-supervision-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/personalDetails/PersonDetailsGenerator.kt index 0dc4f1994d..589e4bc3bc 100644 --- a/projects/manage-supervision-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/personalDetails/PersonDetailsGenerator.kt +++ b/projects/manage-supervision-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/personalDetails/PersonDetailsGenerator.kt @@ -288,12 +288,19 @@ object PersonDetailsGenerator { requiresInterpreter = requiresInterpreter, ) - fun generateDocument(personId: Long, alfrescoId: String, name: String, documentType: String) = PersonDocument( + fun generateDocument( + personId: Long, + alfrescoId: String, + name: String, + documentType: String, + primaryKeyId: Long? = null + ) = PersonDocument( id = IdGenerator.getAndIncrement(), lastUpdated = ZonedDateTime.now().minusDays(1), alfrescoId = alfrescoId, name = name, personId = personId, + primaryKeyId = primaryKeyId, type = documentType ) diff --git a/projects/manage-supervision-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/ScheduleIntegrationTest.kt b/projects/manage-supervision-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/ScheduleIntegrationTest.kt new file mode 100644 index 0000000000..97d513f4b1 --- /dev/null +++ b/projects/manage-supervision-and-delius/src/integrationTest/kotlin/uk/gov/justice/digital/hmpps/ScheduleIntegrationTest.kt @@ -0,0 +1,84 @@ +package uk.gov.justice.digital.hmpps + +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.equalTo +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import uk.gov.justice.digital.hmpps.api.model.schedule.PersonAppointment +import uk.gov.justice.digital.hmpps.api.model.schedule.Schedule +import uk.gov.justice.digital.hmpps.data.generator.ContactGenerator +import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator.OVERVIEW +import uk.gov.justice.digital.hmpps.service.toAppointment +import uk.gov.justice.digital.hmpps.service.toDocument +import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.contentAsJson +import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.withToken + +@AutoConfigureMockMvc +@SpringBootTest(webEnvironment = RANDOM_PORT) +internal class ScheduleIntegrationTest { + @Autowired + lateinit var mockMvc: MockMvc + + @Test + fun `upcoming schedule is returned`() { + + val person = OVERVIEW + val res = mockMvc + .perform(get("/schedule/${person.crn}/upcoming").withToken()) + .andExpect(status().isOk) + .andReturn().response.contentAsJson() + + assertThat(res.personSummary.crn, equalTo(person.crn)) + assertThat(res.appointments[0], equalTo(ContactGenerator.FIRST_APPT_CONTACT.toAppointment())) + } + + @Test + fun `previous schedule is returned`() { + + val person = OVERVIEW + val res = mockMvc + .perform(get("/schedule/${person.crn}/previous").withToken()) + .andExpect(status().isOk) + .andReturn().response.contentAsJson() + assertThat(res.personSummary.crn, equalTo(person.crn)) + assertThat(res.appointments[0], equalTo(ContactGenerator.PREVIOUS_APPT_CONTACT_ABSENT.toAppointment())) + + } + + @Test + fun `previous schedule not found status returned`() { + mockMvc + .perform(get("/schedule/X123456/previous").withToken()) + .andExpect(status().isNotFound) + } + + @Test + fun `Upcomimg schedule not found status returned`() { + mockMvc + .perform(get("/schedule/X123456/upcoming").withToken()) + .andExpect(status().isNotFound) + } + + + @Test + fun `individual appointment is returned`() { + + val person = OVERVIEW + val id = ContactGenerator.NEXT_APPT_CONTACT.id + val res = mockMvc + .perform(get("/schedule/${person.crn}/appointment/${id}").withToken()) + .andExpect(status().isOk) + .andReturn().response.contentAsJson() + val expectedDocs = listOf(ContactGenerator.CONTACT_DOCUMENT_1.toDocument(), ContactGenerator.CONTACT_DOCUMENT_2.toDocument(),) + val expectedAppointment = ContactGenerator.NEXT_APPT_CONTACT.toAppointment().copy(documents = expectedDocs) + assertThat(res.personSummary.crn, equalTo(person.crn)) + assertThat(res.appointment, equalTo(expectedAppointment)) + + } +} diff --git a/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/controller/ScheduleController.kt b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/controller/ScheduleController.kt new file mode 100644 index 0000000000..7397792320 --- /dev/null +++ b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/controller/ScheduleController.kt @@ -0,0 +1,30 @@ +package uk.gov.justice.digital.hmpps.api.controller + +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.security.access.prepost.PreAuthorize +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import uk.gov.justice.digital.hmpps.service.ScheduleService + +@RestController +@Tag(name = "Sentence") +@RequestMapping("/schedule/{crn}") +@PreAuthorize("hasRole('PROBATION_API__MANAGE_A_SUPERVISION__CASE_DETAIL')") +class ScheduleController(private val scheduleService: ScheduleService) { + + @GetMapping("/upcoming") + @Operation(summary = "Gets upcoming schedule information’ ") + fun getUpcomingSchedule(@PathVariable crn: String) = scheduleService.getPersonUpcomingSchedule(crn) + + @GetMapping("/previous") + @Operation(summary = "Gets previous schedule information’ ") + fun getPreviousSchedule(@PathVariable crn: String) = scheduleService.getPersonPreviousSchedule(crn) + + @GetMapping("/appointment/{contactId}") + @Operation(summary = "Gets individual appointment information’ ") + fun getContact(@PathVariable crn: String, @PathVariable contactId: Long) = + scheduleService.getPersonAppointment(crn, contactId) +} \ No newline at end of file diff --git a/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/overview/Overview.kt b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/overview/Overview.kt index cf1f6554bd..6b39995cc8 100644 --- a/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/overview/Overview.kt +++ b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/overview/Overview.kt @@ -1,6 +1,8 @@ package uk.gov.justice.digital.hmpps.api.model.overview data class Overview( + val appointmentsWithoutOutcome: Int = 0, + val absencesWithoutEvidence: Int = 0, val activity: Activity?, val compliance: Compliance?, val personalDetails: PersonalDetails, diff --git a/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/schedule/Appointment.kt b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/schedule/Appointment.kt new file mode 100644 index 0000000000..c033c3e5e0 --- /dev/null +++ b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/schedule/Appointment.kt @@ -0,0 +1,35 @@ +package uk.gov.justice.digital.hmpps.api.model.schedule + +import uk.gov.justice.digital.hmpps.api.model.Name +import uk.gov.justice.digital.hmpps.api.model.personalDetails.Document +import java.time.ZonedDateTime + +data class Appointment( + + val id: Long, + val type: String, + val startDateTime: ZonedDateTime, + val endDateTime: ZonedDateTime?, + val rarToolKit: String?, + val notes: String?, + val isSensitive: Boolean?, + val hasOutcome: Boolean, + val wasAbsent: Boolean?, + val officerName: Name?, + val isInitial: Boolean, + val isNationalStandard: Boolean, + var location: OfficeAddress? = null, + val rescheduled: Boolean, + val didTheyComply: Boolean?, + val absentWaitingEvidence: Boolean?, + val rearrangeOrCancelReason: String?, + val rescheduledBy: Name?, + val repeating: Boolean? = null, + val nonComplianceReason: String?, + val documents: List, + val rarCategory: String?, + val acceptableAbsence: Boolean?, + val acceptableAbsenceReason: String?, + val lastUpdated: ZonedDateTime, + val lastUpdatedBy: Name +) diff --git a/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/schedule/OfficeAddress.kt b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/schedule/OfficeAddress.kt new file mode 100644 index 0000000000..7090226008 --- /dev/null +++ b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/schedule/OfficeAddress.kt @@ -0,0 +1,48 @@ +package uk.gov.justice.digital.hmpps.api.model.schedule + +data class OfficeAddress( + val officeName: String, + val buildingName: String?, + val buildingNumber: String?, + val streetName: String?, + val district: String?, + val town: String?, + val county: String?, + val postcode: String?, + val ldu: String, + val telephoneNumber: String? +) { + companion object { + fun from( + officeName: String, + buildingName: String?, + buildingNumber: String?, + streetName: String?, + district: String?, + town: String?, + county: String?, + postcode: String?, + ldu: String, + telephoneNumber: String? + ): OfficeAddress? = + if ( + buildingName == null && buildingNumber == null && streetName == null && + district == null && town == null && county == null && postcode == null + ) { + null + } else { + OfficeAddress( + officeName, + buildingName, + buildingNumber, + streetName, + district, + town, + county, + postcode, + ldu, + telephoneNumber, + ) + } + } +} \ No newline at end of file diff --git a/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/schedule/PersonAppointment.kt b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/schedule/PersonAppointment.kt new file mode 100644 index 0000000000..87746153a9 --- /dev/null +++ b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/schedule/PersonAppointment.kt @@ -0,0 +1,8 @@ +package uk.gov.justice.digital.hmpps.api.model.schedule + +import uk.gov.justice.digital.hmpps.api.model.PersonSummary + +data class PersonAppointment( + val personSummary: PersonSummary, + val appointment: Appointment +) \ No newline at end of file diff --git a/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/schedule/Schedule.kt b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/schedule/Schedule.kt new file mode 100644 index 0000000000..43f5ff9f0a --- /dev/null +++ b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/model/schedule/Schedule.kt @@ -0,0 +1,8 @@ +package uk.gov.justice.digital.hmpps.api.model.schedule + +import uk.gov.justice.digital.hmpps.api.model.PersonSummary + +data class Schedule( + val personSummary: PersonSummary, + val appointments: List +) \ No newline at end of file diff --git a/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/overview/entity/Contact.kt b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/overview/entity/Contact.kt index 31118e2193..7d892f7623 100644 --- a/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/overview/entity/Contact.kt +++ b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/overview/entity/Contact.kt @@ -4,11 +4,11 @@ import jakarta.persistence.* import org.hibernate.annotations.Immutable import org.hibernate.annotations.SQLRestriction import org.hibernate.type.YesNoConverter -import org.springframework.data.domain.PageRequest -import org.springframework.data.domain.Pageable import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Query import uk.gov.justice.digital.hmpps.datetime.EuropeLondon +import uk.gov.justice.digital.hmpps.exception.NotFoundException +import uk.gov.justice.digital.hmpps.integrations.delius.user.entity.User import java.time.LocalDate import java.time.ZonedDateTime import java.time.format.DateTimeFormatter @@ -43,20 +43,61 @@ class Contact( @Convert(converter = YesNoConverter::class) var attended: Boolean? = null, + @Column(name = "sensitive") + @Convert(converter = YesNoConverter::class) + var sensitive: Boolean? = null, + @Column(name = "complied") @Convert(converter = YesNoConverter::class) var complied: Boolean? = null, - @Column(name = "rqmnt_id") - val requirementId: Long? = null, + @ManyToOne + @JoinColumn(name = "contact_outcome_type_id") + val outcome: ContactOutcome? = null, + + @Column(name = "linked_document_contact_id") + val linkedDocumentContactId: Long? = null, + + @Lob + val notes: String?, + + @ManyToOne + @JoinColumn(name = "rqmnt_id") + val requirement: Requirement? = null, + + @ManyToOne + @JoinColumn(name = "staff_id") + val staff: Staff? = null, + + @ManyToOne + @JoinColumn(name = "office_location_id") + val location: OfficeLocation? = null, @Column(name = "contact_end_time") val endTime: ZonedDateTime? = null, + @Column(name = "last_updated_datetime") + val lastUpdated: ZonedDateTime, + + @ManyToOne + @JoinColumn(name = "last_updated_user_id") + val lastUpdatedUser: User, + @Column(name = "soft_deleted", columnDefinition = "NUMBER", nullable = false) var softDeleted: Boolean = false ) { fun startDateTime(): ZonedDateTime = ZonedDateTime.of(date, startTime.toLocalTime(), EuropeLondon) + fun endDateTime(): ZonedDateTime? = + if (endTime != null) ZonedDateTime.of(date, endTime.toLocalTime(), EuropeLondon) else null + + fun isInitial(): Boolean = setOf( + ContactTypeCode.INITIAL_APPOINTMENT_IN_OFFICE.value, + ContactTypeCode.INITIAL_APPOINTMENT_ON_DOORSTEP.value, + ContactTypeCode.INITIAL_APPOINTMENT_HOME_VISIT.value, + ContactTypeCode.INITIAL_APPOINTMENT_BY_VIDEO.value + ).contains(type.code) + + fun rescheduled(): Boolean = outcome?.code == ContactOutcomeTypeCode.RESCHEDULED.value } @Immutable @@ -76,9 +117,48 @@ class ContactType( @Column val description: String, + + @Column(name = "national_standards_contact") + @Convert(converter = YesNoConverter::class) + val nationalStandardsContact: Boolean = false, ) +@Immutable +@Entity +@Table(name = "r_contact_outcome_type") +class ContactOutcome( + @Id + @Column(name = "contact_outcome_type_id") + val id: Long, + + val code: String, + + val description: String, + + @Column(name = "outcome_attendance") + @Convert(converter = YesNoConverter::class) + val outcomeAttendance: Boolean? = null, + + @Column(name = "outcome_compliant_acceptable") + @Convert(converter = YesNoConverter::class) + val outcomeCompliantAcceptable: Boolean? = null, +) + +enum class ContactOutcomeTypeCode(val value: String) { + RESCHEDULED("RSSR") +} + +enum class ContactTypeCode(val value: String) { + INITIAL_APPOINTMENT_IN_OFFICE("COAI"), + INITIAL_APPOINTMENT_ON_DOORSTEP("CODI"), + INITIAL_APPOINTMENT_HOME_VISIT("COHV"), + INITIAL_APPOINTMENT_BY_VIDEO("COVI") +} + interface ContactRepository : JpaRepository { + + fun findByPersonIdAndId(personId: Long, id: Long): Contact? + @Query( """ select c.* @@ -92,20 +172,168 @@ interface ContactRepository : JpaRepository { """, nativeQuery = true ) - fun findFirstAppointment( + fun findUpComingAppointments( personId: Long, dateNow: String, timeNow: String, - pageable: Pageable = PageRequest.of(0, 1) + ): List + + @Query( + """ + select c.* + from contact c + join r_contact_type ct on c.contact_type_id = ct.contact_type_id + where c.offender_id = :personId and ct.attendance_contact = 'Y' + and (to_char(c.contact_date, 'YYYY-MM-DD') < :dateNow + or (to_char(c.contact_date, 'YYYY-MM-DD') = :dateNow and to_char(c.contact_start_time, 'HH24:MI') < :timeNow)) + and c.soft_deleted = 0 + order by c.contact_date, c.contact_start_time asc + """, + nativeQuery = true + ) + fun findPreviousAppointments( + personId: Long, + dateNow: String, + timeNow: String ): List } +fun ContactRepository.getContact(personId: Long, contactId: Long): Contact = + findByPersonIdAndId(personId, contactId) ?: throw NotFoundException("Contact", "contactId", contactId) + fun ContactRepository.firstAppointment( personId: Long, date: LocalDate = LocalDate.now(), startTime: ZonedDateTime = ZonedDateTime.now() -): Contact? = findFirstAppointment( +): Contact? = findUpComingAppointments( personId, date.format(DateTimeFormatter.ISO_LOCAL_DATE), startTime.format(DateTimeFormatter.ISO_LOCAL_TIME.withZone(EuropeLondon)) -).firstOrNull() \ No newline at end of file +).firstOrNull() + +fun ContactRepository.getUpComingAppointments( + personId: Long, + date: LocalDate = LocalDate.now(), + startTime: ZonedDateTime = ZonedDateTime.now() +): List = findUpComingAppointments( + personId = personId, + dateNow = date.format(DateTimeFormatter.ISO_LOCAL_DATE), + timeNow = startTime.format(DateTimeFormatter.ISO_LOCAL_TIME.withZone(EuropeLondon)), +) + +fun ContactRepository.getPreviousAppointments( + personId: Long, + date: LocalDate = LocalDate.now(), + startTime: ZonedDateTime = ZonedDateTime.now() +): List = findPreviousAppointments( + personId = personId, + dateNow = date.format(DateTimeFormatter.ISO_LOCAL_DATE), + timeNow = startTime.format(DateTimeFormatter.ISO_LOCAL_TIME.withZone(EuropeLondon)), +) + +@Immutable +@Entity +@Table(name = "staff") +class Staff( + + @Column(name = "officer_code", columnDefinition = "char(7)") + val code: String, + + @Column + val forename: String, + + @Column + val surname: String, + + @JoinColumn(name = "probation_area_id") + @OneToOne + val provider: Provider, + + @Id + @Column(name = "staff_id") + val id: Long +) { + fun isUnallocated(): Boolean { + return code.endsWith("U") + } +} + +@Immutable +@Entity +@Table(name = "probation_area") +class Provider( + @Column(name = "code", columnDefinition = "char(3)") + val code: String, + + val description: String, + + @Id + @Column(name = "probation_area_id") + val id: Long, + + @Column(name = "end_date") + var endDate: LocalDate? = null +) + +@Immutable +@Entity +@Table(name = "office_location") +class OfficeLocation( + + @Column(name = "code", columnDefinition = "char(7)") + val code: String, + + val description: String, + val buildingName: String?, + val buildingNumber: String?, + val streetName: String?, + val district: String?, + val townCity: String?, + val county: String?, + val postcode: String?, + val telephoneNumber: String?, + val startDate: LocalDate, + val endDate: LocalDate?, + + @JoinColumn(name = "district_id") + @ManyToOne + val ldu: District, + + @Id + @Column(name = "office_location_id") + val id: Long +) + +@Immutable +@Entity +@Table(name = "district") +class District( + + @Column(name = "code") + val code: String, + + val description: String, + + @ManyToOne + @JoinColumn(name = "borough_id") + val borough: Borough, + + @Id + @Column(name = "district_id") + val id: Long +) + +@Immutable +@Entity +@Table(name = "borough") +class Borough( + + @Column(name = "code") + val code: String, + + val description: String, + + @Id + @Column(name = "borough_id") + val id: Long +) \ No newline at end of file diff --git a/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/overview/entity/Requirement.kt b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/overview/entity/Requirement.kt index 0d487f7e0f..b626de365a 100644 --- a/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/overview/entity/Requirement.kt +++ b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/overview/entity/Requirement.kt @@ -69,5 +69,6 @@ class RequirementMainCategory( @Column(name = "rqmnt_type_main_category_id", nullable = false) val id: Long, val code: String, + val description: String ) diff --git a/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/personalDetails/entity/Document.kt b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/personalDetails/entity/Document.kt index defd7fce8a..a7a3f53a7f 100644 --- a/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/personalDetails/entity/Document.kt +++ b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/personalDetails/entity/Document.kt @@ -23,6 +23,9 @@ class PersonDocument( @Column(name = "offender_id") val personId: Long, + @Column(name = "primary_key_id") + val primaryKeyId: Long?, + @Column(name = "alfresco_document_id") val alfrescoId: String, @@ -42,6 +45,8 @@ class PersonDocument( interface DocumentRepository : JpaRepository { fun findByPersonId(personId: Long): List + fun findByPersonIdAndPrimaryKeyId(personId: Long, primaryKeyId: Long): List + @Query("select d.name from PersonDocument d join Person p on p.id = d.personId and p.crn = :crn and d.alfrescoId = :alfrescoId") fun findNameByPersonCrnAndAlfrescoId(crn: String, alfrescoId: String): String? } diff --git a/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/OverviewService.kt b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/OverviewService.kt index b7a7524d95..c9202faa0f 100644 --- a/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/OverviewService.kt +++ b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/OverviewService.kt @@ -29,6 +29,10 @@ class OverviewService( val personalCircumstances = personalCircumstanceRepository.findCurrentCircumstances(person.id) val disabilities = disabilityRepository.findByPersonId(person.id) val personalDetails = person.toPersonalDetails(personalCircumstances, disabilities, provisions) + val previousAppointments = contactRepository.getPreviousAppointments(person.id) + val previousAppointmentNoOutcome = + previousAppointments.filter { it.attended != false && it.outcome == null }.size + val absentWithoutEvidence = previousAppointments.filter { it.attended == false && it.outcome == null }.size val schedule = Schedule(contactRepository.firstAppointment(person.id)?.toNextAppointment()) val events = eventRepository.findByPersonId(person.id) val activeEvents = events.filter { it.active } @@ -40,6 +44,8 @@ class OverviewService( return Overview( + appointmentsWithoutOutcome = previousAppointmentNoOutcome, + absencesWithoutEvidence = absentWithoutEvidence, personalDetails = personalDetails, schedule = schedule, previousOrders = PreviousOrders(previousOrdersBreached, previousOrders), @@ -95,7 +101,7 @@ class OverviewService( fun Disability.toDisability() = uk.gov.justice.digital.hmpps.api.model.overview.Disability(description = type.description) - fun uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.Provision.toProvision() = + fun Provision.toProvision() = uk.gov.justice.digital.hmpps.api.model.overview.Provision(description = type.description) fun Contact.toNextAppointment() = diff --git a/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/ScheduleService.kt b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/ScheduleService.kt new file mode 100644 index 0000000000..e812c4e8ea --- /dev/null +++ b/projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/service/ScheduleService.kt @@ -0,0 +1,96 @@ +package uk.gov.justice.digital.hmpps.service + +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import uk.gov.justice.digital.hmpps.api.model.Name +import uk.gov.justice.digital.hmpps.api.model.personalDetails.Document +import uk.gov.justice.digital.hmpps.api.model.schedule.Appointment +import uk.gov.justice.digital.hmpps.api.model.schedule.OfficeAddress +import uk.gov.justice.digital.hmpps.api.model.schedule.PersonAppointment +import uk.gov.justice.digital.hmpps.api.model.schedule.Schedule +import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.* +import uk.gov.justice.digital.hmpps.integrations.delius.personalDetails.entity.DocumentRepository + +@Service +class ScheduleService( + private val personRepository: PersonRepository, + private val contactRepository: ContactRepository, + private val documentRepository: DocumentRepository +) { + + @Transactional + fun getPersonAppointment(crn: String, contactId: Long): PersonAppointment { + val summary = personRepository.getSummary(crn) + val contact = contactRepository.getContact(summary.id, contactId) + val documents = if (contact.linkedDocumentContactId != null) + documentRepository.findByPersonIdAndPrimaryKeyId(contact.personId, contact.linkedDocumentContactId) + .map { it.toDocument() } else emptyList() + return PersonAppointment( + personSummary = summary.toPersonSummary(), + appointment = contact.toAppointment(documents) + ) + } + + @Transactional + fun getPersonUpcomingSchedule(crn: String): Schedule { + val summary = personRepository.getSummary(crn) + val appointments = contactRepository.getUpComingAppointments(summary.id) + return Schedule( + personSummary = summary.toPersonSummary(), + appointments = appointments.map { it.toAppointment() }) + } + + @Transactional + fun getPersonPreviousSchedule(crn: String): Schedule { + val summary = personRepository.getSummary(crn) + val appointments = contactRepository.getPreviousAppointments(summary.id) + return Schedule( + personSummary = summary.toPersonSummary(), + appointments = appointments.map { it.toAppointment() }) + } +} + +fun OfficeLocation.toOfficeAddress() = OfficeAddress.from( + officeName = description, + buildingName = buildingName, + buildingNumber = buildingNumber, + streetName = streetName, + district = district, + town = townCity, + county = county, + ldu = ldu.description, + postcode = postcode, + telephoneNumber = telephoneNumber +) + +fun Contact.toAppointment(documents: List = emptyList()) = Appointment( + id = id, + type = type.description, + isNationalStandard = type.nationalStandardsContact, + isSensitive = sensitive, + didTheyComply = complied, + acceptableAbsence = outcome?.outcomeAttendance == false && outcome.outcomeCompliantAcceptable == true, + acceptableAbsenceReason = if (outcome?.outcomeAttendance == false && outcome.outcomeCompliantAcceptable == true) + outcome.description else null, + absentWaitingEvidence = attended == false && outcome == null, + documents = documents, + startDateTime = startDateTime(), + endDateTime = endDateTime(), + hasOutcome = outcome != null, + isInitial = isInitial(), + lastUpdated = lastUpdated, + lastUpdatedBy = Name(forename = lastUpdatedUser.forename, surname = lastUpdatedUser.surname), + wasAbsent = outcome?.outcomeAttendance, + nonComplianceReason = if (outcome?.outcomeCompliantAcceptable == false) type.description else null, + notes = notes, + location = location?.toOfficeAddress(), + officerName = staff?.forename?.let { Name(forename = it, surname = staff.surname) }, + rarCategory = requirement?.mainCategory?.description, + rarToolKit = requirement?.mainCategory?.description, + rescheduled = rescheduled(), + rearrangeOrCancelReason = if (rescheduled()) outcome?.description else null, + rescheduledBy = if (rescheduled()) Name( + forename = lastUpdatedUser.forename, + surname = lastUpdatedUser.surname + ) else null +) diff --git a/projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/api/controller/ScheduleControllerTest.kt b/projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/api/controller/ScheduleControllerTest.kt new file mode 100644 index 0000000000..b6012f3cec --- /dev/null +++ b/projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/api/controller/ScheduleControllerTest.kt @@ -0,0 +1,83 @@ +package uk.gov.justice.digital.hmpps.api.controller + +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.equalTo +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.whenever +import uk.gov.justice.digital.hmpps.api.model.Name +import uk.gov.justice.digital.hmpps.api.model.PersonSummary +import uk.gov.justice.digital.hmpps.api.model.schedule.PersonAppointment +import uk.gov.justice.digital.hmpps.api.model.schedule.Schedule +import uk.gov.justice.digital.hmpps.data.generator.ContactGenerator +import uk.gov.justice.digital.hmpps.service.ScheduleService +import uk.gov.justice.digital.hmpps.service.toAppointment +import java.time.LocalDate + +@ExtendWith(MockitoExtension::class) +internal class ScheduleControllerTest { + + @Mock + lateinit var scheduleService: ScheduleService + + @InjectMocks + lateinit var controller: ScheduleController + + private lateinit var personSummary: PersonSummary + + @BeforeEach + fun setup() { + personSummary = PersonSummary( + Name(forename = "TestName", middleName = null, surname = "TestSurname"), pnc = "Test PNC", + crn = "CRN", + dateOfBirth = LocalDate.now(), offenderId = 1L + ) + } + + @Test + fun `calls get get upcoming function `() { + val crn = "X000005" + val expectedResponse = Schedule( + personSummary = personSummary, + appointments = listOfNotNull( + ContactGenerator.FIRST_APPT_CONTACT.toAppointment(), + ContactGenerator.NEXT_APPT_CONTACT.toAppointment() + ), + ) + whenever(scheduleService.getPersonUpcomingSchedule(crn)).thenReturn(expectedResponse) + val res = controller.getUpcomingSchedule(crn) + assertThat(res, equalTo(expectedResponse)) + } + + @Test + fun `calls get get previous function `() { + val crn = "X000005" + val expectedResponse = Schedule( + personSummary = personSummary, + appointments = listOfNotNull( + ContactGenerator.PREVIOUS_APPT_CONTACT.toAppointment(), + ContactGenerator.PREVIOUS_APPT_CONTACT_ABSENT.toAppointment() + ), + ) + whenever(scheduleService.getPersonPreviousSchedule(crn)).thenReturn(expectedResponse) + val res = controller.getPreviousSchedule(crn) + assertThat(res, equalTo(expectedResponse)) + } + + @Test + fun `calls get get appointment function `() { + val crn = "X000005" + val id = ContactGenerator.PREVIOUS_APPT_CONTACT_ABSENT.id + val expectedResponse = PersonAppointment( + personSummary = personSummary, + appointment = ContactGenerator.PREVIOUS_APPT_CONTACT_ABSENT.toAppointment() + ) + whenever(scheduleService.getPersonAppointment(crn, id)).thenReturn(expectedResponse) + val res = controller.getContact(crn, id) + assertThat(res, equalTo(expectedResponse)) + } +} \ No newline at end of file diff --git a/projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/OverviewServiceTest.kt b/projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/OverviewServiceTest.kt index 30eaa67535..8de59b0a0f 100644 --- a/projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/OverviewServiceTest.kt +++ b/projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/OverviewServiceTest.kt @@ -61,7 +61,7 @@ internal class OverviewServiceTest { whenever(disabilityRepository.findByPersonId(any())).thenReturn(emptyList()) whenever(personalCircumstanceRepository.findCurrentCircumstances(any())).thenReturn(PersonGenerator.PERSONAL_CIRCUMSTANCES) - whenever(contactRepository.findFirstAppointment(any(), any(), any(), any())).thenReturn( + whenever(contactRepository.findUpComingAppointments(any(), any(), any())).thenReturn( listOf(FIRST_APPT_CONTACT) ) whenever(requirementRepository.getRarDays(any())).thenReturn( diff --git a/projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonalDetailsServiceTest.kt b/projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonalDetailsServiceTest.kt index bfa8b65143..9f9ab607a7 100644 --- a/projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonalDetailsServiceTest.kt +++ b/projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/PersonalDetailsServiceTest.kt @@ -22,6 +22,7 @@ import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.* import uk.gov.justice.digital.hmpps.integrations.delius.personalDetails.entity.DocumentRepository import uk.gov.justice.digital.hmpps.integrations.delius.personalDetails.entity.PersonAddressRepository import uk.gov.justice.digital.hmpps.integrations.delius.personalDetails.entity.PersonalContactRepository +import uk.gov.justice.digital.hmpps.utils.Summary import java.time.LocalDate @ExtendWith(MockitoExtension::class) @@ -155,15 +156,4 @@ internal class PersonalDetailsServiceTest { val res = service.getPersonAddresses(crn) assertThat(res, equalTo(expectedResponse)) } - - data class Summary( - override val id: Long, - override val forename: String, - override val secondName: String? = null, - override val thirdName: String? = null, - override val surname: String, - override val crn: String, - override val pnc: String?, - override val dateOfBirth: LocalDate - ) : PersonSummaryEntity } \ No newline at end of file diff --git a/projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ScheduleServiceTest.kt b/projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ScheduleServiceTest.kt new file mode 100644 index 0000000000..170b55e835 --- /dev/null +++ b/projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/service/ScheduleServiceTest.kt @@ -0,0 +1,88 @@ +package uk.gov.justice.digital.hmpps.service + +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.equalTo +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.any +import org.mockito.kotlin.whenever +import uk.gov.justice.digital.hmpps.data.generator.ContactGenerator +import uk.gov.justice.digital.hmpps.data.generator.personalDetails.PersonDetailsGenerator.PERSONAL_DETAILS +import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.ContactRepository +import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.PersonRepository +import uk.gov.justice.digital.hmpps.integrations.delius.personalDetails.entity.DocumentRepository +import uk.gov.justice.digital.hmpps.utils.Summary + +@ExtendWith(MockitoExtension::class) +internal class ScheduleServiceTest { + + @Mock + lateinit var personRepository: PersonRepository + + @Mock + lateinit var contactRepository: ContactRepository + + @Mock + lateinit var documentRepository: DocumentRepository + + @InjectMocks + lateinit var service: ScheduleService + + private lateinit var personSummary: Summary + + @BeforeEach + fun setup() { + personSummary = Summary( + id = PERSONAL_DETAILS.id, + forename = PERSONAL_DETAILS.forename, + secondName = PERSONAL_DETAILS.secondName, + surname = PERSONAL_DETAILS.surname, crn = PERSONAL_DETAILS.crn, pnc = PERSONAL_DETAILS.pnc, + dateOfBirth = PERSONAL_DETAILS.dateOfBirth + ) + } + + @Test + fun `calls get upcoming schedule function`() { + val crn = "X000005" + val expectedContacts = listOf(ContactGenerator.NEXT_APPT_CONTACT, ContactGenerator.FIRST_APPT_CONTACT) + whenever(personRepository.findSummary(crn)).thenReturn(personSummary) + whenever(contactRepository.findUpComingAppointments(any(), any(), any())).thenReturn(expectedContacts) + val res = service.getPersonUpcomingSchedule(crn) + assertThat( + res.personSummary, equalTo(PERSONAL_DETAILS.toSummary()) + ) + assertThat(res.appointments, equalTo(expectedContacts.map { it.toAppointment() })) + } + + @Test + fun `calls get appointment function`() { + val crn = "X000005" + val expectedContact = ContactGenerator.NEXT_APPT_CONTACT + whenever(personRepository.findSummary(crn)).thenReturn(personSummary) + whenever(contactRepository.findByPersonIdAndId(any(), any())).thenReturn(expectedContact) + whenever(documentRepository.findByPersonIdAndPrimaryKeyId(any(), any())).thenReturn(emptyList()) + val res = service.getPersonAppointment(crn, ContactGenerator.NEXT_APPT_CONTACT.id) + assertThat( + res.personSummary, equalTo(PERSONAL_DETAILS.toSummary()) + ) + assertThat(res.appointment, equalTo(expectedContact.toAppointment())) + } + + @Test + fun `calls get previous schedule function`() { + val crn = "X000005" + val expectedContacts = + listOf(ContactGenerator.PREVIOUS_APPT_CONTACT_ABSENT, ContactGenerator.PREVIOUS_APPT_CONTACT) + whenever(personRepository.findSummary(crn)).thenReturn(personSummary) + whenever(contactRepository.findPreviousAppointments(any(), any(), any())).thenReturn(expectedContacts) + val res = service.getPersonPreviousSchedule(crn) + assertThat( + res.personSummary, equalTo(PERSONAL_DETAILS.toSummary()) + ) + assertThat(res.appointments, equalTo(expectedContacts.map { it.toAppointment() })) + } +} \ No newline at end of file diff --git a/projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/utils/Summary.kt b/projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/utils/Summary.kt new file mode 100644 index 0000000000..3a3aa2742b --- /dev/null +++ b/projects/manage-supervision-and-delius/src/test/kotlin/uk/gov/justice/digital/hmpps/utils/Summary.kt @@ -0,0 +1,15 @@ +package uk.gov.justice.digital.hmpps.utils + +import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.PersonSummaryEntity +import java.time.LocalDate + +data class Summary( + override val id: Long, + override val forename: String, + override val secondName: String? = null, + override val thirdName: String? = null, + override val surname: String, + override val crn: String, + override val pnc: String?, + override val dateOfBirth: LocalDate +) : PersonSummaryEntity \ No newline at end of file