Skip to content

Commit 22bd573

Browse files
* PI-1961 * PI-1961 create alert and add audit
1 parent 825242e commit 22bd573

File tree

14 files changed

+434
-68
lines changed

14 files changed

+434
-68
lines changed

projects/resettlement-passport-and-delius/deploy/database/access.yml

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ database:
22
access:
33
username_key: /resettlement-passport-and-delius/db-username
44
password_key: /resettlement-passport-and-delius/db-password
5+
tables:
6+
- audited_interaction
7+
- contact
58

69
audit:
710
username: ResettlementPassportAndDelius
8-
forename: Probation Integration # TODO change this to something meaningful for your service
11+
forename: Resettlement Passport
912
surname: Service

projects/resettlement-passport-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/DataLoader.kt

+41-19
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,19 @@ import org.springframework.boot.context.event.ApplicationReadyEvent
77
import org.springframework.context.ApplicationListener
88
import org.springframework.stereotype.Component
99
import org.springframework.transaction.annotation.Transactional
10-
import uk.gov.justice.digital.hmpps.data.generator.AddressGenerator
11-
import uk.gov.justice.digital.hmpps.data.generator.AppointmentGenerator
12-
import uk.gov.justice.digital.hmpps.data.generator.NSIGenerator
13-
import uk.gov.justice.digital.hmpps.data.generator.NSIManagerGenerator
14-
import uk.gov.justice.digital.hmpps.data.generator.NSIStatusGenerator
15-
import uk.gov.justice.digital.hmpps.data.generator.NSITypeGenerator
16-
import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator
17-
import uk.gov.justice.digital.hmpps.data.generator.ProviderGenerator
18-
import uk.gov.justice.digital.hmpps.data.generator.ReferenceDataGenerator
19-
import uk.gov.justice.digital.hmpps.data.generator.RegistrationGenerator
20-
import uk.gov.justice.digital.hmpps.data.generator.UserGenerator
10+
import uk.gov.justice.digital.hmpps.api.model.CreateAppointment
11+
import uk.gov.justice.digital.hmpps.audit.BusinessInteraction
12+
import uk.gov.justice.digital.hmpps.data.generator.*
2113
import uk.gov.justice.digital.hmpps.datetime.EuropeLondon
14+
import uk.gov.justice.digital.hmpps.entity.BusinessInteractionCode
2215
import uk.gov.justice.digital.hmpps.entity.Category
2316
import uk.gov.justice.digital.hmpps.entity.Level
2417
import uk.gov.justice.digital.hmpps.entity.Person
2518
import uk.gov.justice.digital.hmpps.user.AuditUserRepository
2619
import java.time.LocalDate
2720
import java.time.LocalTime
2821
import java.time.ZonedDateTime
22+
import java.util.*
2923

3024
@Component
3125
@ConditionalOnProperty("seed.database")
@@ -41,6 +35,9 @@ class DataLoader(
4135

4236
@Transactional
4337
override fun onApplicationEvent(are: ApplicationReadyEvent) {
38+
BusinessInteractionCode.entries.forEach {
39+
em.persist(BusinessInteraction(IdGenerator.getAndIncrement(), it.code, ZonedDateTime.now()))
40+
}
4441
em.saveAll(
4542
NSITypeGenerator.DTR,
4643
NSIStatusGenerator.INITIATED,
@@ -75,6 +72,29 @@ class DataLoader(
7572
)
7673

7774
createAppointments(PersonGenerator.DEFAULT)
75+
76+
createAppointmentData()
77+
}
78+
79+
fun createAppointmentData() {
80+
val conflictPerson = PersonGenerator.CREATE_APPOINTMENT
81+
val conflictManager = PersonGenerator.generateManager(PersonGenerator.CREATE_APPOINTMENT)
82+
em.saveAll(
83+
*AppointmentGenerator.APPOINTMENT_TYPES.toTypedArray(),
84+
conflictPerson,
85+
conflictManager,
86+
AppointmentGenerator.generate(
87+
conflictPerson,
88+
AppointmentGenerator.ATTENDANCE_TYPE,
89+
LocalDate.now().plusDays(7),
90+
ZonedDateTime.now().plusDays(7),
91+
ZonedDateTime.now().plusDays(7).plusHours(1),
92+
location = null,
93+
probationAreaId = conflictManager.probationAreaId,
94+
team = conflictManager.team,
95+
staff = conflictManager.staff
96+
)
97+
)
7898
}
7999

80100
fun EntityManager.saveAll(vararg any: Any) = any.forEach { persist(it) }
@@ -89,17 +109,19 @@ class DataLoader(
89109
date,
90110
start,
91111
start.plusMinutes(30),
92-
if (start.minute == 30) AppointmentGenerator.DEFAULT_LOCATION else null,
93-
ProviderGenerator.DEFAULT_STAFF,
94-
if (start.isAfter(ZonedDateTime.now())) {
95-
null
96-
} else {
97-
AppointmentGenerator.ATTENDED_OUTCOME
98-
},
99-
if (start.minute == 0) {
112+
probationAreaId = ProviderGenerator.DEFAULT_AREA.id,
113+
team = ProviderGenerator.DEFAULT_TEAM,
114+
staff = ProviderGenerator.DEFAULT_STAFF,
115+
location = if (start.minute == 30) AppointmentGenerator.DEFAULT_LOCATION else null,
116+
description = if (start.minute == 0) {
100117
"On the hour"
101118
} else {
102119
null
120+
},
121+
outcome = if (start.isAfter(ZonedDateTime.now())) {
122+
null
123+
} else {
124+
AppointmentGenerator.ATTENDED_OUTCOME
103125
}
104126
)
105127
}

projects/resettlement-passport-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/AppointmentGenerator.kt

+26-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
package uk.gov.justice.digital.hmpps.data.generator
22

3-
import uk.gov.justice.digital.hmpps.entity.Appointment
4-
import uk.gov.justice.digital.hmpps.entity.AppointmentOutcome
5-
import uk.gov.justice.digital.hmpps.entity.AppointmentType
6-
import uk.gov.justice.digital.hmpps.entity.Location
7-
import uk.gov.justice.digital.hmpps.entity.Person
8-
import uk.gov.justice.digital.hmpps.entity.Staff
3+
import uk.gov.justice.digital.hmpps.api.model.CreateAppointment
4+
import uk.gov.justice.digital.hmpps.entity.*
95
import java.time.LocalDate
106
import java.time.ZonedDateTime
117

@@ -21,6 +17,7 @@ object AppointmentGenerator {
2117
townCity = "Heath",
2218
postcode = "H34 7TH"
2319
)
20+
val APPOINTMENT_TYPES = CreateAppointment.Type.entries.map { generateType(it.code, attendanceType = true) }
2421

2522
fun generateType(
2623
code: String,
@@ -67,11 +64,33 @@ object AppointmentGenerator {
6764
date: LocalDate,
6865
startTime: ZonedDateTime,
6966
endTime: ZonedDateTime?,
67+
externalReference: String? = null,
7068
location: Location?,
69+
notes: String? = null,
70+
probationAreaId: Long,
71+
team: Team,
7172
staff: Staff,
7273
outcome: AppointmentOutcome? = null,
7374
description: String? = null,
7475
softDeleted: Boolean = false,
76+
version: Long = 0,
7577
id: Long = IdGenerator.getAndIncrement()
76-
) = Appointment(person, type, date, startTime, endTime, location, staff, description, outcome, softDeleted, id)
78+
) = Appointment(
79+
person,
80+
type,
81+
date,
82+
startTime,
83+
endTime,
84+
notes,
85+
probationAreaId,
86+
team,
87+
staff,
88+
externalReference,
89+
description,
90+
location,
91+
outcome,
92+
softDeleted,
93+
version,
94+
id
95+
)
7796
}

projects/resettlement-passport-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/PersonGenerator.kt

+8-4
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ package uk.gov.justice.digital.hmpps.data.generator
33
import uk.gov.justice.digital.hmpps.entity.Person
44
import uk.gov.justice.digital.hmpps.entity.PersonManager
55
import uk.gov.justice.digital.hmpps.entity.Staff
6+
import uk.gov.justice.digital.hmpps.entity.Team
67

78
object PersonGenerator {
89
val DEFAULT = generate("X123123", "A1234YZ")
9-
val DEFAULT_MANAGER = generateManager(staff = ProviderGenerator.DEFAULT_STAFF)
10+
val DEFAULT_MANAGER = generateManager(DEFAULT)
11+
val CREATE_APPOINTMENT = generate("C123456")
1012

1113
fun generate(
1214
crn: String,
@@ -22,10 +24,12 @@ object PersonGenerator {
2224
)
2325

2426
fun generateManager(
25-
person: Person = PersonGenerator.DEFAULT,
26-
staff: Staff,
27+
person: Person,
28+
team: Team = ProviderGenerator.DEFAULT_TEAM,
29+
staff: Staff = ProviderGenerator.DEFAULT_STAFF,
30+
probationAreaId: Long = ProviderGenerator.DEFAULT_AREA.id,
2731
active: Boolean = true,
2832
softDeleted: Boolean = false,
2933
id: Long = IdGenerator.getAndIncrement()
30-
) = PersonManager(person, staff, softDeleted, active, id)
34+
) = PersonManager(person, team, staff, probationAreaId, softDeleted, active, id)
3135
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package uk.gov.justice.digital.hmpps
2+
3+
import org.hamcrest.MatcherAssert.assertThat
4+
import org.hamcrest.Matchers.equalTo
5+
import org.junit.jupiter.api.Assertions.assertNotNull
6+
import org.junit.jupiter.api.Test
7+
import org.springframework.beans.factory.annotation.Autowired
8+
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
9+
import org.springframework.boot.test.context.SpringBootTest
10+
import org.springframework.data.domain.PageRequest
11+
import org.springframework.test.web.servlet.MockMvc
12+
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
13+
import org.springframework.test.web.servlet.result.MockMvcResultMatchers
14+
import uk.gov.justice.digital.hmpps.api.model.CreateAppointment
15+
import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator
16+
import uk.gov.justice.digital.hmpps.entity.AlertRepository
17+
import uk.gov.justice.digital.hmpps.entity.AppointmentRepository
18+
import uk.gov.justice.digital.hmpps.test.CustomMatchers.isCloseTo
19+
import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.withJson
20+
import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.withToken
21+
import java.time.ZonedDateTime
22+
23+
@AutoConfigureMockMvc
24+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
25+
internal class CreateAppointmentIntTests {
26+
@Autowired
27+
internal lateinit var mockMvc: MockMvc
28+
29+
@Autowired
30+
internal lateinit var appointmentRepository: AppointmentRepository
31+
32+
@Autowired
33+
internal lateinit var alertRepository: AlertRepository
34+
35+
@Test
36+
fun `create appointment when offender does not exist retuns a 404 response`() {
37+
mockMvc.perform(
38+
post("/appointments/D123456")
39+
.withToken()
40+
.withJson(
41+
CreateAppointment(
42+
CreateAppointment.Type.Accommodation,
43+
ZonedDateTime.now().plusDays(1),
44+
ZonedDateTime.now().plusDays(1)
45+
)
46+
)
47+
).andExpect(MockMvcResultMatchers.status().isNotFound)
48+
}
49+
50+
@Test
51+
fun `create appointment retuns a 409 when conflicting appointment`() {
52+
val start = ZonedDateTime.now().plusDays(7).plusMinutes(10)
53+
mockMvc.perform(
54+
post("/appointments/${PersonGenerator.CREATE_APPOINTMENT.crn}")
55+
.withToken()
56+
.withJson(
57+
CreateAppointment(CreateAppointment.Type.Health, start, start.plusMinutes(30))
58+
)
59+
).andExpect(MockMvcResultMatchers.status().isConflict)
60+
}
61+
62+
@Test
63+
fun `create appointment ending before start returns bad request`() {
64+
val start = ZonedDateTime.now().plusDays(7).plusMinutes(10)
65+
mockMvc.perform(
66+
post("/appointments/${PersonGenerator.CREATE_APPOINTMENT.crn}")
67+
.withToken()
68+
.withJson(
69+
CreateAppointment(CreateAppointment.Type.Finance, start, start.minusSeconds(1))
70+
)
71+
).andExpect(MockMvcResultMatchers.status().isBadRequest)
72+
}
73+
74+
@Test
75+
fun `create a new appointment`() {
76+
val person = PersonGenerator.CREATE_APPOINTMENT
77+
val start = ZonedDateTime.now().plusDays(1)
78+
val notes = "Resettlement Passport Notes"
79+
val create = CreateAppointment(CreateAppointment.Type.SkillsAndWork, start, start.plusHours(1), notes)
80+
81+
mockMvc.perform(
82+
post("/appointments/${person.crn}")
83+
.withToken()
84+
.withJson(create)
85+
).andExpect(MockMvcResultMatchers.status().isCreated)
86+
87+
val appointment = appointmentRepository.findAppointmentsFor(
88+
person.crn,
89+
start.toLocalDate(),
90+
start.toLocalDate(),
91+
PageRequest.of(0, 1)
92+
).first()
93+
94+
assertThat(appointment.type.code, equalTo(create.type.code))
95+
assertThat(appointment.date, equalTo(start.toLocalDate()))
96+
assertThat(appointment.startTime, isCloseTo(start))
97+
assertThat(appointment.notes, equalTo(notes))
98+
assertThat(appointment.externalReference, equalTo(create.urn))
99+
100+
val alert = alertRepository.findAll().firstOrNull { it.contactId == appointment.id }
101+
assertNotNull(alert)
102+
}
103+
}

projects/resettlement-passport-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/api/controller/AppointmentController.kt

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
package uk.gov.justice.digital.hmpps.api.controller
22

33
import org.springframework.data.domain.PageRequest
4+
import org.springframework.http.HttpStatus
45
import org.springframework.security.access.prepost.PreAuthorize
5-
import org.springframework.web.bind.annotation.GetMapping
6-
import org.springframework.web.bind.annotation.PathVariable
7-
import org.springframework.web.bind.annotation.RequestMapping
8-
import org.springframework.web.bind.annotation.RequestParam
9-
import org.springframework.web.bind.annotation.RestController
6+
import org.springframework.web.bind.annotation.*
107
import uk.gov.justice.digital.hmpps.api.model.Appointment
8+
import uk.gov.justice.digital.hmpps.api.model.CreateAppointment
119
import uk.gov.justice.digital.hmpps.service.AppointmentService
1210
import java.time.LocalDate
1311

@@ -26,6 +24,12 @@ class AppointmentController(private val appointmentService: AppointmentService)
2624
appointmentService.findAppointmentsFor(crn, startDate, endDate, PageRequest.of(page, size)).let {
2725
ResultSet(it.content, it.totalElements, it.totalPages, page, size)
2826
}
27+
28+
@PreAuthorize("hasRole('PROBATION_API__RESETTLEMENT_PASSPORT__APPOINTMENT_RW')")
29+
@PostMapping("/{crn}")
30+
@ResponseStatus(HttpStatus.CREATED)
31+
fun createAppointment(@PathVariable crn: String, @RequestBody createAppointment: CreateAppointment) =
32+
appointmentService.createAppointment(crn, createAppointment)
2933
}
3034

3135
data class ResultSet<T>(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package uk.gov.justice.digital.hmpps.api.model
2+
3+
import java.time.ZonedDateTime
4+
import java.util.*
5+
6+
data class CreateAppointment(
7+
val type: Type,
8+
val start: ZonedDateTime,
9+
val end: ZonedDateTime,
10+
val notes: String? = null,
11+
val uuid: UUID = UUID.randomUUID()
12+
) {
13+
val urn = URN_PREFIX + uuid
14+
15+
enum class Type(val code: String) {
16+
Accommodation("RP1"),
17+
ThinkingAndBehaviour("RP2"),
18+
FamilyAndCommunity("RP3"),
19+
DrugsAndAlcohol("RP4"),
20+
SkillsAndWork("RP5"),
21+
Finance("RP6"),
22+
Health("RP7"),
23+
Benefits("RP8")
24+
}
25+
26+
companion object {
27+
const val URN_PREFIX = "urn:uk:gov:hmpps:resettlement-passport-service:appointment:"
28+
}
29+
}

0 commit comments

Comments
 (0)