Skip to content

Commit b2a4fb3

Browse files
Man 109 backend create appointment in mms (#4365)
* MAN-109 - add new api * MAN-109 - update audit params * MAN-109 - add integration test * MAN-109 - add integration test * MAN-109 - update integration test * MAN-109 - refactor db layer and update tests * MAN-109 - add error logic * MAN-109 - add error logic * MAN-109 - update data saved to db and add service test * MAN-109 - update data saved to db and add service test * MAN-109 - update db object * MAN-109 - remove duplicated code * MAN-109 - make CreateAppointment.end as a optional parameter * MAN-109 - update integration test * MAN-109 - add return object * MAN-109 - update integration test * MAN-109 - delete repo class not needed * MAN-109 - undo delete of repo class not, due to ci build failure * MAN-109 - delete of repo class not required * MAN-109 - comment out code temporarily, due to ci failure * MAN-109 - fix deployment error * MAN-109 - update service and tests * MAN-109 - update database access file * MAN-109 - update database access file to remove sequence section. * Formatting changes * MAN-109 - set mandatory db columns * MAN-109 - apply review comments * MAN-109 - comment added * MAN-109 - do not set a default value to uuid --------- Co-authored-by: probation-integration-bot[bot] <177347787+probation-integration-bot[bot]@users.noreply.github.com>
1 parent 434a481 commit b2a4fb3

File tree

16 files changed

+684
-4
lines changed

16 files changed

+684
-4
lines changed

projects/manage-supervision-and-delius/deploy/database/access.yml

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ database:
22
access:
33
username_key: /manage-supervision-and-delius/db-username
44
password_key: /manage-supervision-and-delius/db-password
5+
tables:
6+
- contact
57

68
audit:
79
username: ManageSupervisionAndDelius

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

+7
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@ 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.audit.BusinessInteraction
1011
import uk.gov.justice.digital.hmpps.data.generator.*
1112
import uk.gov.justice.digital.hmpps.data.generator.CourtAppearanceGenerator.COURT_APPEARANCE
1213
import uk.gov.justice.digital.hmpps.data.generator.personalDetails.PersonDetailsGenerator
14+
import uk.gov.justice.digital.hmpps.integrations.delius.audit.BusinessInteractionCode
1315
import uk.gov.justice.digital.hmpps.user.AuditUserRepository
16+
import java.time.ZonedDateTime
1417

1518
@Component
1619
@ConditionalOnProperty("seed.database")
@@ -27,7 +30,11 @@ class DataLoader(
2730
@Transactional
2831
override fun onApplicationEvent(are: ApplicationReadyEvent) {
2932

33+
BusinessInteractionCode.entries.forEach {
34+
entityManager.persist(BusinessInteraction(IdGenerator.getAndIncrement(), it.code, ZonedDateTime.now()))
35+
}
3036
entityManager.persistAll(
37+
*AppointmentGenerator.APPOINTMENT_TYPES.toTypedArray(),
3138
ContactGenerator.DEFAULT_PROVIDER,
3239
ContactGenerator.DEFAULT_BOROUGH,
3340
ContactGenerator.DEFAULT_DISTRICT,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package uk.gov.justice.digital.hmpps.data.generator
2+
3+
import uk.gov.justice.digital.hmpps.api.model.appointment.CreateAppointment
4+
import uk.gov.justice.digital.hmpps.integrations.delius.overview.entity.ContactType
5+
6+
object AppointmentGenerator {
7+
8+
val APPOINTMENT_TYPES = CreateAppointment.Type.entries.map { generateType(it.code, attendanceType = true) }
9+
10+
fun generateType(
11+
code: String,
12+
description: String = "Description for $code",
13+
attendanceType: Boolean,
14+
id: Long = IdGenerator.getAndIncrement()
15+
) = ContactType(IdGenerator.getAndIncrement(), code, true, description)
16+
}

projects/manage-supervision-and-delius/src/dev/kotlin/uk/gov/justice/digital/hmpps/data/generator/OffenderManagerGenerator.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ object OffenderManagerGenerator {
3535
ContactGenerator.DEFAULT_PROVIDER,
3636
TEAM,
3737
STAFF_2,
38-
LocalDate.now()
38+
LocalDate.now(),
39+
active = false
3940
)
4041
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
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.Test
6+
import org.junit.jupiter.params.ParameterizedTest
7+
import org.junit.jupiter.params.provider.MethodSource
8+
import org.springframework.beans.factory.annotation.Autowired
9+
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
10+
import org.springframework.boot.test.context.SpringBootTest
11+
import org.springframework.test.web.servlet.MockMvc
12+
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
13+
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
14+
import org.springframework.test.web.servlet.result.MockMvcResultMatchers
15+
import uk.gov.justice.digital.hmpps.api.model.appointment.CreateAppointment
16+
import uk.gov.justice.digital.hmpps.api.model.appointment.CreatedAppointment
17+
import uk.gov.justice.digital.hmpps.data.generator.PersonGenerator
18+
import uk.gov.justice.digital.hmpps.integrations.delius.sentence.entity.AppointmentRepository
19+
import uk.gov.justice.digital.hmpps.test.CustomMatchers.isCloseTo
20+
import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.contentAsJson
21+
import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.withJson
22+
import uk.gov.justice.digital.hmpps.test.MockMvcExtensions.withToken
23+
import java.time.ZonedDateTime
24+
import java.util.*
25+
26+
@AutoConfigureMockMvc
27+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
28+
class CreateAppointmentIntegrationTests {
29+
30+
@Autowired
31+
internal lateinit var mockMvc: MockMvc
32+
33+
@Autowired
34+
internal lateinit var appointmentRepository: AppointmentRepository
35+
36+
@Test
37+
fun `unauthorized status returned`() {
38+
mockMvc
39+
.perform(MockMvcRequestBuilders.get("/appointments/D123456"))
40+
.andExpect(MockMvcResultMatchers.status().isUnauthorized)
41+
}
42+
43+
@Test
44+
fun `when offender does not exist retuns a 404 response`() {
45+
mockMvc.perform(
46+
post("/appointments/D123456")
47+
.withToken()
48+
.withJson(
49+
CreateAppointment(
50+
CreateAppointment.Type.HomeVisitToCaseNS,
51+
ZonedDateTime.now().plusDays(1),
52+
ZonedDateTime.now().plusDays(2),
53+
1,
54+
1,
55+
UUID.randomUUID()
56+
)
57+
)
58+
).andExpect(MockMvcResultMatchers.status().isNotFound)
59+
}
60+
61+
@Test
62+
fun `appointment end date before start returns bad request`() {
63+
mockMvc.perform(
64+
post("/appointments/${PersonGenerator.PERSON_1.crn}")
65+
.withToken()
66+
.withJson(
67+
CreateAppointment(
68+
CreateAppointment.Type.InitialAppointmentInOfficeNS,
69+
ZonedDateTime.now().plusDays(2),
70+
ZonedDateTime.now().plusDays(1),
71+
1,
72+
PersonGenerator.EVENT_1.id,
73+
UUID.randomUUID()
74+
)
75+
)
76+
).andExpect(MockMvcResultMatchers.status().isBadRequest)
77+
}
78+
79+
@ParameterizedTest
80+
@MethodSource("createAppointments")
81+
fun `create a new appointment`(createAppointment: CreateAppointment) {
82+
val person = PersonGenerator.PERSON_1
83+
84+
val response = mockMvc.perform(
85+
post("/appointments/${person.crn}")
86+
.withToken()
87+
.withJson(createAppointment)
88+
)
89+
.andExpect(MockMvcResultMatchers.status().isCreated)
90+
.andReturn().response.contentAsJson<CreatedAppointment>()
91+
92+
val appointment = appointmentRepository.findById(response.id).get()
93+
94+
assertThat(appointment.type.code, equalTo(createAppointment.type.code))
95+
assertThat(appointment.date, equalTo(createAppointment.start.toLocalDate()))
96+
assertThat(appointment.startTime, isCloseTo(createAppointment.start))
97+
assertThat(appointment.externalReference, equalTo(createAppointment.urn))
98+
assertThat(appointment.eventId, equalTo(createAppointment.eventId))
99+
100+
appointmentRepository.delete(appointment)
101+
}
102+
103+
companion object {
104+
@JvmStatic
105+
fun createAppointments() = listOf(
106+
CreateAppointment(
107+
CreateAppointment.Type.PlannedOfficeVisitNS,
108+
ZonedDateTime.now().plusDays(1),
109+
ZonedDateTime.now().plusDays(2),
110+
1,
111+
PersonGenerator.EVENT_1.id,
112+
UUID.randomUUID()
113+
),
114+
CreateAppointment(
115+
CreateAppointment.Type.InitialAppointmentInOfficeNS,
116+
ZonedDateTime.now().plusDays(1),
117+
null,
118+
1,
119+
PersonGenerator.EVENT_1.id,
120+
UUID.randomUUID()
121+
)
122+
)
123+
}
124+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package uk.gov.justice.digital.hmpps.api.controller
2+
3+
import io.swagger.v3.oas.annotations.tags.Tag
4+
import org.springframework.http.HttpStatus
5+
import org.springframework.security.access.prepost.PreAuthorize
6+
import org.springframework.web.bind.annotation.*
7+
import uk.gov.justice.digital.hmpps.api.model.appointment.CreateAppointment
8+
import uk.gov.justice.digital.hmpps.service.AppointmentService
9+
10+
@RestController
11+
@Tag(name = "Sentence")
12+
@RequestMapping("/appointments/{crn}")
13+
@PreAuthorize("hasRole('PROBATION_API__MANAGE_A_SUPERVISION__CASE_DETAIL')")
14+
class AppointmentController(private val appointmentService: AppointmentService) {
15+
16+
@PostMapping
17+
@ResponseStatus(HttpStatus.CREATED)
18+
fun createAppointment(@PathVariable crn: String, @RequestBody createAppointment: CreateAppointment) =
19+
appointmentService.createAppointment(crn, createAppointment)
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package uk.gov.justice.digital.hmpps.api.model.appointment
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnore
4+
import java.time.ZonedDateTime
5+
import java.util.*
6+
7+
data class CreateAppointment(
8+
val type: Type,
9+
val start: ZonedDateTime,
10+
val end: ZonedDateTime?,
11+
val interval: Int,
12+
val eventId: Long,
13+
val uuid: UUID,
14+
val requirementId: Long? = null,
15+
val licenceConditionId: Long? = null,
16+
val numberOfAppointments: Int? = null,
17+
val until: ZonedDateTime? = null
18+
) {
19+
@JsonIgnore
20+
val urn = URN_PREFIX + uuid
21+
22+
enum class Type(val code: String) {
23+
HomeVisitToCaseNS("CHVS"),
24+
InitialAppointmentInOfficeNS("COAI"),
25+
PlannedOfficeVisitNS("COAP"),
26+
InitialAppointmentHomeVisitNS("COHV")
27+
}
28+
29+
companion object {
30+
const val URN_PREFIX = "urn:uk:gov:hmpps:manage-supervision-service:appointment:"
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package uk.gov.justice.digital.hmpps.api.model.appointment
2+
3+
data class CreatedAppointment(
4+
val id: Long
5+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package uk.gov.justice.digital.hmpps.integrations.delius.audit
2+
3+
import uk.gov.justice.digital.hmpps.audit.InteractionCode
4+
5+
enum class BusinessInteractionCode(override val code: String) : InteractionCode {
6+
ADD_CONTACT("CLBI003")
7+
}

projects/manage-supervision-and-delius/src/main/kotlin/uk/gov/justice/digital/hmpps/integrations/delius/overview/entity/Contact.kt

+6-1
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,13 @@ class Contact(
9696
val lastUpdatedUser: User,
9797

9898
@Column(name = "soft_deleted", columnDefinition = "NUMBER", nullable = false)
99-
val softDeleted: Boolean = false
99+
val softDeleted: Boolean = false,
100+
101+
val partitionAreaId: Long = 0,
102+
103+
val createdByUserId: Long = 0
100104
) {
105+
101106
fun startDateTime(): ZonedDateTime =
102107
if (startTime != null) ZonedDateTime.of(date, startTime.toLocalTime(), EuropeLondon) else
103108
ZonedDateTime.of(date, date.atStartOfDay().toLocalTime(), EuropeLondon)

0 commit comments

Comments
 (0)