Skip to content

Commit 464450b

Browse files
authored
CDPS-1125 Update distinguishing marks response format (#29)
1 parent ee25c11 commit 464450b

File tree

10 files changed

+273
-86
lines changed

10 files changed

+273
-86
lines changed

src/main/kotlin/uk/gov/justice/digital/hmpps/personintegrationapi/common/client/PrisonApiClient.kt

+17-17
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ import uk.gov.justice.digital.hmpps.personintegrationapi.common.client.request.U
2020
import uk.gov.justice.digital.hmpps.personintegrationapi.common.client.request.UpdateBirthPlace
2121
import uk.gov.justice.digital.hmpps.personintegrationapi.common.client.request.UpdateNationality
2222
import uk.gov.justice.digital.hmpps.personintegrationapi.common.client.request.UpdateReligion
23+
import uk.gov.justice.digital.hmpps.personintegrationapi.common.client.response.DistinguishingMarkPrisonDto
2324
import uk.gov.justice.digital.hmpps.personintegrationapi.common.client.response.MilitaryRecordPrisonDto
2425
import uk.gov.justice.digital.hmpps.personintegrationapi.common.client.response.PhysicalAttributes
25-
import uk.gov.justice.digital.hmpps.personintegrationapi.corepersonrecord.dto.response.DistinguishingMarkDto
2626

2727
@HttpExchange("/api")
2828
interface PrisonApiClient {
@@ -68,30 +68,41 @@ interface PrisonApiClient {
6868
@RequestBody updateNationality: UpdateReligion,
6969
): ResponseEntity<Void>
7070

71+
@GetExchange("/{offenderNo}/core-person-record/physical-attributes")
72+
fun getPhysicalAttributes(
73+
@PathVariable offenderNo: String,
74+
): ResponseEntity<PhysicalAttributes>
75+
76+
@PutExchange("/{offenderNo}/core-person-record/physical-attributes")
77+
fun updatePhysicalAttributes(
78+
@PathVariable offenderNo: String,
79+
@RequestBody physicalAttributes: PhysicalAttributesRequest,
80+
): ResponseEntity<Void>
81+
7182
@GetExchange("/person/{prisonerNumber}/distinguishing-marks")
7283
fun getDistinguishingMarks(
7384
@PathVariable prisonerNumber: String,
74-
): ResponseEntity<List<DistinguishingMarkDto>>
85+
): ResponseEntity<List<DistinguishingMarkPrisonDto>>
7586

7687
@GetExchange("/person/{prisonerNumber}/distinguishing-mark/{markId}")
7788
fun getDistinguishingMark(
7889
@PathVariable prisonerNumber: String,
7990
@PathVariable markId: Int,
80-
): ResponseEntity<DistinguishingMarkDto>
91+
): ResponseEntity<DistinguishingMarkPrisonDto>
8192

8293
@PutExchange("/person/{prisonerNumber}/distinguishing-mark/{markId}")
8394
fun updateDistinguishingMark(
8495
@RequestBody request: DistinguishingMarkUpdateRequest,
8596
@PathVariable prisonerNumber: String,
8697
@PathVariable markId: Int,
87-
): ResponseEntity<DistinguishingMarkDto>
98+
): ResponseEntity<DistinguishingMarkPrisonDto>
8899

89100
@PostExchange("/person/{prisonerNumber}/distinguishing-mark", accept = [APPLICATION_JSON_VALUE, MULTIPART_FORM_DATA_VALUE])
90101
fun createDistinguishingMark(
91102
@RequestPart(name = "file") file: MultipartFile?,
92103
@ModelAttribute request: DistinguishingMarkCreateRequest,
93104
@PathVariable prisonerNumber: String,
94-
): ResponseEntity<DistinguishingMarkDto>
105+
): ResponseEntity<DistinguishingMarkPrisonDto>
95106

96107
@GetExchange("/person/photo/{imageId}")
97108
fun getDistinguishingMarkImage(
@@ -103,16 +114,5 @@ interface PrisonApiClient {
103114
@RequestPart(name = "file") file: MultipartFile,
104115
@PathVariable prisonerNumber: String,
105116
@PathVariable markId: Int,
106-
): ResponseEntity<DistinguishingMarkDto>
107-
108-
@GetExchange("/{offenderNo}/core-person-record/physical-attributes")
109-
fun getPhysicalAttributes(
110-
@PathVariable offenderNo: String,
111-
): ResponseEntity<PhysicalAttributes>
112-
113-
@PutExchange("/{offenderNo}/core-person-record/physical-attributes")
114-
fun updatePhysicalAttributes(
115-
@PathVariable offenderNo: String,
116-
@RequestBody physicalAttributes: PhysicalAttributesRequest,
117-
): ResponseEntity<Void>
117+
): ResponseEntity<DistinguishingMarkPrisonDto>
118118
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package uk.gov.justice.digital.hmpps.personintegrationapi.common.client.response
2+
3+
import java.time.LocalDateTime
4+
5+
data class DistinguishingMarkPrisonDto(
6+
val id: Int,
7+
val bookingId: Long,
8+
val offenderNo: String,
9+
val bodyPart: ReferenceDataCode? = null,
10+
val markType: ReferenceDataCode? = null,
11+
val side: ReferenceDataCode? = null,
12+
val partOrientation: ReferenceDataCode? = null,
13+
val comment: String? = null,
14+
val createdAt: LocalDateTime? = null,
15+
val createdBy: String? = null,
16+
val photographUuids: List<DistinguishingMarkImageDetailPrisonDto> = listOf(),
17+
)
18+
19+
data class DistinguishingMarkImageDetailPrisonDto(
20+
val id: Long,
21+
val latest: Boolean = false,
22+
)
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package uk.gov.justice.digital.hmpps.personintegrationapi.common.client.response
22

3+
import uk.gov.justice.digital.hmpps.personintegrationapi.common.dto.ReferenceDataValue
4+
35
data class ReferenceDataCode(
46
val domain: String,
57
val code: String,
@@ -8,4 +10,10 @@ data class ReferenceDataCode(
810
val listSeq: Int,
911
val parentCode: String? = null,
1012
val parentDomain: String? = null,
11-
)
13+
) {
14+
fun toReferenceDataValue(): ReferenceDataValue = ReferenceDataValue(
15+
id = "${domain}_$code",
16+
code = code,
17+
description = description,
18+
)
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package uk.gov.justice.digital.hmpps.personintegrationapi.common.dto
2+
3+
import com.fasterxml.jackson.annotation.JsonInclude
4+
import com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL
5+
import io.swagger.v3.oas.annotations.media.Schema
6+
7+
@Schema(description = "Reference Data Value - a reference data code selected as the value for a field")
8+
@JsonInclude(NON_NULL)
9+
data class ReferenceDataValue(
10+
@Schema(description = "Id", example = "FOOD_ALLERGY_MILK")
11+
val id: String,
12+
13+
@Schema(description = "Code", example = "MILK")
14+
val code: String,
15+
16+
@Schema(description = "Description of the reference data code", example = "Milk")
17+
val description: String,
18+
)

src/main/kotlin/uk/gov/justice/digital/hmpps/personintegrationapi/corepersonrecord/dto/response/DistinguishingMarkDto.kt

+9-20
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package uk.gov.justice.digital.hmpps.personintegrationapi.corepersonrecord.dto.r
33
import com.fasterxml.jackson.annotation.JsonInclude
44
import com.fasterxml.jackson.annotation.JsonInclude.Include
55
import io.swagger.v3.oas.annotations.media.Schema
6+
import uk.gov.justice.digital.hmpps.personintegrationapi.common.dto.ReferenceDataValue
67
import java.time.LocalDateTime
78

89
@JsonInclude(Include.NON_NULL)
@@ -26,29 +27,17 @@ data class DistinguishingMarkDto(
2627
)
2728
val offenderNo: String? = null,
2829

29-
@Schema(
30-
description = "The body part that the mark is on",
31-
example = "TORSO",
32-
)
33-
val bodyPart: String? = null,
30+
@Schema(description = "The body part that the mark is on")
31+
val bodyPart: ReferenceDataValue? = null,
3432

35-
@Schema(
36-
description = "The type of distinguishign mark (e.g. scar, tattoo)",
37-
example = "SCAR",
38-
)
39-
val markType: String? = null,
33+
@Schema(description = "The type of distinguishign mark (e.g. scar, tattoo)")
34+
val markType: ReferenceDataValue? = null,
4035

41-
@Schema(
42-
description = "The side of the body the mark is on",
43-
example = "L",
44-
)
45-
val side: String? = null,
36+
@Schema(description = "The side of the body the mark is on")
37+
val side: ReferenceDataValue? = null,
4638

47-
@Schema(
48-
description = "The orientation of the mark on the body part (e.g. upper, lower)",
49-
example = "UPP",
50-
)
51-
val partOrientation: String? = null,
39+
@Schema(description = "The orientation of the mark on the body part (e.g. upper, lower)")
40+
val partOrientation: ReferenceDataValue? = null,
5241

5342
@Schema(description = "Comments about the distinguishing mark")
5443
val comment: String? = null,

src/main/kotlin/uk/gov/justice/digital/hmpps/personintegrationapi/corepersonrecord/service/DistinguishingMarksService.kt

+38-6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import uk.gov.justice.digital.hmpps.personintegrationapi.common.client.request.D
88
import uk.gov.justice.digital.hmpps.personintegrationapi.common.client.request.DistinguishingMarkUpdateRequest
99
import uk.gov.justice.digital.hmpps.personintegrationapi.common.client.request.SourceSystem.NOMIS
1010
import uk.gov.justice.digital.hmpps.personintegrationapi.common.client.request.toSourceSystem
11+
import uk.gov.justice.digital.hmpps.personintegrationapi.common.client.response.DistinguishingMarkPrisonDto
1112
import uk.gov.justice.digital.hmpps.personintegrationapi.corepersonrecord.dto.response.DistinguishingMarkDto
13+
import uk.gov.justice.digital.hmpps.personintegrationapi.corepersonrecord.dto.response.DistinguishingMarkImageDetail
1214

1315
@Service
1416
class DistinguishingMarksService(
@@ -17,14 +19,24 @@ class DistinguishingMarksService(
1719
fun getDistinguishingMarks(
1820
prisonerNumber: String,
1921
sourceSystem: String,
20-
): ResponseEntity<List<DistinguishingMarkDto>> = when (sourceSystem.toSourceSystem()) {
21-
NOMIS -> prisonApiClient.getDistinguishingMarks(prisonerNumber)
22+
): ResponseEntity<List<DistinguishingMarkDto>> {
23+
when (sourceSystem.toSourceSystem()) {
24+
NOMIS -> {
25+
val response = prisonApiClient.getDistinguishingMarks(prisonerNumber)
26+
27+
return if (response.statusCode.is2xxSuccessful) {
28+
ResponseEntity.ok(response.body?.map { toDto(it) })
29+
} else {
30+
ResponseEntity.status(response.statusCode).build()
31+
}
32+
}
33+
}
2234
}
2335

2436
fun getDistinguishingMark(markId: String, sourceSystem: String): ResponseEntity<DistinguishingMarkDto> = when (sourceSystem.toSourceSystem()) {
2537
NOMIS -> {
2638
val (prisonerNumber, sequenceId) = parseMarkId(markId)
27-
prisonApiClient.getDistinguishingMark(prisonerNumber, sequenceId)
39+
mappedResponse(prisonApiClient.getDistinguishingMark(prisonerNumber, sequenceId))
2840
}
2941
}
3042

@@ -35,7 +47,7 @@ class DistinguishingMarksService(
3547
): ResponseEntity<DistinguishingMarkDto> = when (sourceSystem.toSourceSystem()) {
3648
NOMIS -> {
3749
val (prisonerNumber, sequenceId) = parseMarkId(markId)
38-
prisonApiClient.updateDistinguishingMark(request, prisonerNumber, sequenceId)
50+
mappedResponse(prisonApiClient.updateDistinguishingMark(request, prisonerNumber, sequenceId))
3951
}
4052
}
4153

@@ -45,7 +57,7 @@ class DistinguishingMarksService(
4557
prisonerNumber: String,
4658
sourceSystem: String,
4759
): ResponseEntity<DistinguishingMarkDto> = when (sourceSystem.toSourceSystem()) {
48-
NOMIS -> prisonApiClient.createDistinguishingMark(file, request, prisonerNumber)
60+
NOMIS -> mappedResponse(prisonApiClient.createDistinguishingMark(file, request, prisonerNumber))
4961
}
5062

5163
fun getDistinguishingMarkImage(imageId: String, sourceSystem: String): ResponseEntity<ByteArray> = when (sourceSystem.toSourceSystem()) {
@@ -59,7 +71,7 @@ class DistinguishingMarksService(
5971
): ResponseEntity<DistinguishingMarkDto> = when (sourceSystem.toSourceSystem()) {
6072
NOMIS -> {
6173
val (prisonerNumber, sequenceId) = parseMarkId(markId)
62-
prisonApiClient.addDistinguishingMarkImage(file, prisonerNumber, sequenceId)
74+
mappedResponse(prisonApiClient.addDistinguishingMarkImage(file, prisonerNumber, sequenceId))
6375
}
6476
}
6577

@@ -70,4 +82,24 @@ class DistinguishingMarksService(
7082
}
7183
return Pair(tokens[0], tokens[1].toInt())
7284
}
85+
86+
private fun mappedResponse(response: ResponseEntity<DistinguishingMarkPrisonDto>): ResponseEntity<DistinguishingMarkDto> = if (response.statusCode.is2xxSuccessful) {
87+
ResponseEntity.ok(response.body?.let { toDto(it) })
88+
} else {
89+
ResponseEntity.status(response.statusCode).build()
90+
}
91+
92+
private fun toDto(value: DistinguishingMarkPrisonDto): DistinguishingMarkDto = DistinguishingMarkDto(
93+
id = value.id,
94+
bookingId = value.bookingId,
95+
offenderNo = value.offenderNo,
96+
bodyPart = value.bodyPart?.toReferenceDataValue(),
97+
markType = value.markType?.toReferenceDataValue(),
98+
side = value.side?.toReferenceDataValue(),
99+
partOrientation = value.partOrientation?.toReferenceDataValue(),
100+
comment = value.comment,
101+
createdAt = value.createdAt,
102+
createdBy = value.createdBy,
103+
photographUuids = value.photographUuids.map { DistinguishingMarkImageDetail(it.id, it.latest) },
104+
)
73105
}

src/test/kotlin/uk/gov/justice/digital/hmpps/personintegrationapi/common/resolver/DistinguishingMarkCreateRequestResolverTest.kt src/test/kotlin/uk/gov/justice/digital/hmpps/personintegrationapi/common/resolver/DistinguishingMarkPrisonDtoCreateRequestResolverTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import uk.gov.justice.digital.hmpps.personintegrationapi.common.client.request.D
1717
import uk.gov.justice.digital.hmpps.personintegrationapi.common.client.request.DistinguishingMarkUpdateRequest
1818

1919
@ExtendWith(MockitoExtension::class)
20-
class DistinguishingMarkCreateRequestResolverTest {
20+
class DistinguishingMarkPrisonDtoCreateRequestResolverTest {
2121

2222
@Test
2323
fun `maps supported request correctly`() {

src/test/kotlin/uk/gov/justice/digital/hmpps/personintegrationapi/corepersonrecord/resource/DistinguishingMarksV1ResourceIntTest.kt

+15-14
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import org.springframework.mock.web.MockMultipartFile
1212
import org.springframework.web.multipart.MultipartFile
1313
import org.springframework.web.reactive.function.BodyInserters
1414
import uk.gov.justice.digital.hmpps.personintegrationapi.common.client.request.DistinguishingMarkUpdateRequest
15+
import uk.gov.justice.digital.hmpps.personintegrationapi.common.dto.ReferenceDataValue
1516
import uk.gov.justice.digital.hmpps.personintegrationapi.corepersonrecord.CorePersonRecordRoleConstants
1617
import uk.gov.justice.digital.hmpps.personintegrationapi.corepersonrecord.dto.response.DistinguishingMarkDto
1718
import uk.gov.justice.digital.hmpps.personintegrationapi.corepersonrecord.dto.response.DistinguishingMarkImageDetail
@@ -26,7 +27,7 @@ class DistinguishingMarksV1ResourceIntTest : IntegrationTestBase() {
2627

2728
@DisplayName("GET v1/distinguishing-marks")
2829
@Nested
29-
inner class GetDistinguishingMarks {
30+
inner class GetDistinguishingMarksPrisonDto {
3031

3132
@Nested
3233
inner class Security {
@@ -80,7 +81,7 @@ class DistinguishingMarksV1ResourceIntTest : IntegrationTestBase() {
8081

8182
@DisplayName("GET v1/distinguishing-mark/{markId}")
8283
@Nested
83-
inner class GetDistinguishingMarkById {
84+
inner class GetDistinguishingMarkPrisonDtoById {
8485

8586
@Nested
8687
inner class Security {
@@ -133,7 +134,7 @@ class DistinguishingMarksV1ResourceIntTest : IntegrationTestBase() {
133134

134135
@DisplayName("PUT v1/distinguishing-mark/{markId}")
135136
@Nested
136-
inner class UpdateDistinguishingMark {
137+
inner class UpdateDistinguishingMarkPrisonDto {
137138

138139
@Nested
139140
inner class Security {
@@ -190,7 +191,7 @@ class DistinguishingMarksV1ResourceIntTest : IntegrationTestBase() {
190191

191192
@DisplayName("POST v1/distinguishing-mark/{prisonerNumber}")
192193
@Nested
193-
inner class CreateDistinguishingMark {
194+
inner class CreateDistinguishingMarkPrisonDto {
194195

195196
@Nested
196197
inner class Security {
@@ -252,7 +253,7 @@ class DistinguishingMarksV1ResourceIntTest : IntegrationTestBase() {
252253

253254
@DisplayName("GET v1/distinguishing-mark/image/{imageId}")
254255
@Nested
255-
inner class GetDistinguishingMarkImage {
256+
inner class GetDistinguishingMarkPrisonDtoImage {
256257

257258
@Nested
258259
inner class Security {
@@ -305,7 +306,7 @@ class DistinguishingMarksV1ResourceIntTest : IntegrationTestBase() {
305306

306307
@DisplayName("POST v1/distinguishing-mark/{markId}/image")
307308
@Nested
308-
inner class AddDistinguishingMarkImage {
309+
inner class AddDistinguishingMarkPrisonDtoImage {
309310

310311
@Nested
311312
inner class Security {
@@ -375,10 +376,10 @@ class DistinguishingMarksV1ResourceIntTest : IntegrationTestBase() {
375376
id = 1,
376377
bookingId = -1,
377378
offenderNo = "A1234AA",
378-
bodyPart = "LEG",
379-
markType = "TAT",
380-
side = "R",
381-
partOrientation = "LOW",
379+
bodyPart = ReferenceDataValue("BODY_PART_LEG", "LEG", "Leg"),
380+
markType = ReferenceDataValue("MARK_TYPE_TAT", "TAT", "Tattoo"),
381+
side = ReferenceDataValue("SIDE_R", "R", "Right"),
382+
partOrientation = ReferenceDataValue("PART_ORIENT_LOW", "LOW", "Low"),
382383
comment = "Some comment",
383384
createdAt = LocalDateTime.parse("2025-01-01T00:00:00"),
384385
createdBy = "USER",
@@ -392,10 +393,10 @@ class DistinguishingMarksV1ResourceIntTest : IntegrationTestBase() {
392393
id = 2,
393394
bookingId = -1,
394395
offenderNo = "A1234AA",
395-
bodyPart = "ARM",
396-
markType = "SCAR",
397-
side = "L",
398-
partOrientation = "UPP",
396+
bodyPart = ReferenceDataValue("BODY_PART_ARM", "ARM", "Arm"),
397+
markType = ReferenceDataValue("MARK_TYPE_SCAR", "SCAR", "Scar"),
398+
side = ReferenceDataValue("SIDE_L", "L", "Left"),
399+
partOrientation = ReferenceDataValue("PART_ORIENT_UPP", "UPP", "Upper"),
399400
comment = "Some comment",
400401
createdAt = LocalDateTime.parse("2025-01-01T00:00:00"),
401402
createdBy = "USER",

0 commit comments

Comments
 (0)