Skip to content

Commit f3d0551

Browse files
PRC-415: Sync address phone components and integration test refactoring.
1 parent 135c9e4 commit f3d0551

23 files changed

+1387
-225
lines changed

helm_deploy/hmpps-organisations-api/values.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ generic-service:
3939
FEATURE_EVENT_ORGANISATIONS_API_ORGANISATION_ADDRESS_CREATED: true
4040
FEATURE_EVENT_ORGANISATIONS_API_ORGANISATION_ADDRESS_UPDATED: true
4141
FEATURE_EVENT_ORGANISATIONS_API_ORGANISATION_ADDRESS_DELETED: true
42+
FEATURE_EVENT_ORGANISATIONS_API_ORGANISATION_ADDRESS_PHONE_CREATED: true
43+
FEATURE_EVENT_ORGANISATIONS_API_ORGANISATION_ADDRESS_PHONE_UPDATED: true
44+
FEATURE_EVENT_ORGANISATIONS_API_ORGANISATION_ADDRESS_PHONE_DELETED: true
4245
FEATURE_EVENT_ORGANISATIONS_API_ORGANISATION_TYPES_UPDATED: true
4346

4447

src/main/kotlin/uk/gov/justice/digital/hmpps/organisationsapi/entity/OrganisationAddressPhoneEntity.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ data class OrganisationAddressPhoneEntity(
2727
@Column(updatable = false)
2828
val createdTime: LocalDateTime,
2929

30-
val updatedBy: String?,
30+
val updatedBy: String? = null,
3131

32-
val updatedTime: LocalDateTime?,
32+
val updatedTime: LocalDateTime? = null,
3333
)

src/main/kotlin/uk/gov/justice/digital/hmpps/organisationsapi/facade/SyncFacade.kt

+43
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package uk.gov.justice.digital.hmpps.organisationsapi.facade
22

33
import org.springframework.stereotype.Service
4+
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncCreateAddressPhoneRequest
45
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncCreateAddressRequest
56
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncCreateEmailRequest
67
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncCreateOrganisationRequest
78
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncCreatePhoneRequest
89
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncCreateWebRequest
10+
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncUpdateAddressPhoneRequest
911
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncUpdateAddressRequest
1012
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncUpdateEmailRequest
1113
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncUpdateOrganisationRequest
@@ -15,6 +17,7 @@ import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncUpda
1517
import uk.gov.justice.digital.hmpps.organisationsapi.service.events.OutboundEvent
1618
import uk.gov.justice.digital.hmpps.organisationsapi.service.events.OutboundEventsService
1719
import uk.gov.justice.digital.hmpps.organisationsapi.service.events.Source
20+
import uk.gov.justice.digital.hmpps.organisationsapi.service.sync.SyncAddressPhoneService
1821
import uk.gov.justice.digital.hmpps.organisationsapi.service.sync.SyncAddressService
1922
import uk.gov.justice.digital.hmpps.organisationsapi.service.sync.SyncEmailService
2023
import uk.gov.justice.digital.hmpps.organisationsapi.service.sync.SyncOrganisationService
@@ -47,6 +50,7 @@ class SyncFacade(
4750
private val syncEmailService: SyncEmailService,
4851
private val syncWebService: SyncWebService,
4952
private val syncAddressService: SyncAddressService,
53+
private val syncAddressPhoneService: SyncAddressPhoneService,
5054
private val syncTypesService: SyncTypesService,
5155
private val outboundEventsService: OutboundEventsService,
5256
) {
@@ -230,6 +234,45 @@ class SyncFacade(
230234
)
231235
}
232236

237+
// ================================================================
238+
// Organisation address phone numbers
239+
// ================================================================
240+
241+
fun getAddressPhoneById(organisationAddressPhoneId: Long) =
242+
syncAddressPhoneService.getAddressPhoneById(organisationAddressPhoneId)
243+
244+
fun createAddressPhone(request: SyncCreateAddressPhoneRequest) = syncAddressPhoneService.createAddressPhone(request)
245+
.also {
246+
outboundEventsService.send(
247+
outboundEvent = OutboundEvent.ORGANISATION_ADDRESS_PHONE_CREATED,
248+
organisationId = it.organisationId,
249+
identifier = it.organisationAddressPhoneId,
250+
source = Source.NOMIS,
251+
)
252+
}
253+
254+
fun updateAddressPhone(organisationAddressPhoneId: Long, request: SyncUpdateAddressPhoneRequest) =
255+
syncAddressPhoneService.updateAddressPhone(organisationAddressPhoneId, request)
256+
.also {
257+
outboundEventsService.send(
258+
outboundEvent = OutboundEvent.ORGANISATION_ADDRESS_PHONE_UPDATED,
259+
organisationId = it.organisationId,
260+
identifier = it.organisationAddressPhoneId,
261+
source = Source.NOMIS,
262+
)
263+
}
264+
265+
fun deleteAddressPhone(organisationAddressPhoneId: Long) =
266+
syncAddressPhoneService.deleteAddressPhone(organisationAddressPhoneId)
267+
.also {
268+
outboundEventsService.send(
269+
outboundEvent = OutboundEvent.ORGANISATION_ADDRESS_PHONE_DELETED,
270+
organisationId = it.organisationId,
271+
identifier = it.organisationAddressPhoneId,
272+
source = Source.NOMIS,
273+
)
274+
}
275+
233276
// ================================================================
234277
// Organisation types
235278
// ================================================================
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package uk.gov.justice.digital.hmpps.organisationsapi.mapping.sync
2+
3+
import uk.gov.justice.digital.hmpps.organisationsapi.entity.OrganisationAddressPhoneEntity
4+
import uk.gov.justice.digital.hmpps.organisationsapi.entity.OrganisationPhoneEntity
5+
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncCreateAddressPhoneRequest
6+
import uk.gov.justice.digital.hmpps.organisationsapi.model.response.sync.SyncAddressPhoneResponse
7+
8+
fun OrganisationAddressPhoneEntity.toModel(phoneEntity: OrganisationPhoneEntity) = SyncAddressPhoneResponse(
9+
organisationAddressPhoneId = this.organisationAddressPhoneId,
10+
organisationAddressId = this.organisationAddressId,
11+
organisationPhoneId = this.organisationPhoneId,
12+
organisationId = this.organisationId,
13+
phoneType = phoneEntity.phoneType,
14+
phoneNumber = phoneEntity.phoneNumber,
15+
extNumber = phoneEntity.extNumber,
16+
createdBy = this.createdBy,
17+
createdTime = this.createdTime,
18+
updatedBy = this.updatedBy,
19+
updatedTime = this.updatedTime,
20+
)
21+
22+
fun SyncCreateAddressPhoneRequest.toEntity(phoneEntity: OrganisationPhoneEntity) = OrganisationAddressPhoneEntity(
23+
organisationAddressPhoneId = 0L,
24+
organisationAddressId = this.organisationAddressId,
25+
organisationPhoneId = phoneEntity.organisationPhoneId,
26+
organisationId = phoneEntity.organisationId,
27+
createdBy = this.createdBy,
28+
createdTime = this.createdTime,
29+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync
2+
3+
import io.swagger.v3.oas.annotations.media.Schema
4+
import java.time.LocalDateTime
5+
6+
@Schema(description = "Request to create an address-linked phone number for an organisation")
7+
data class SyncCreateAddressPhoneRequest(
8+
@Schema(description = "Unique identifier for the address to link this number with", example = "123")
9+
val organisationAddressId: Long,
10+
11+
@Schema(description = "Type of phone", example = "MOB")
12+
val phoneType: String,
13+
14+
@Schema(description = "Phone number", example = "+1234567890")
15+
val phoneNumber: String,
16+
17+
@Schema(description = "Extension number", example = "123")
18+
val extNumber: String? = null,
19+
20+
@Schema(description = "User who created the entry", example = "admin")
21+
val createdBy: String,
22+
23+
@Schema(description = "The timestamp of when the phone was created", example = "2024-01-01T00:00:00Z")
24+
val createdTime: LocalDateTime = LocalDateTime.now(),
25+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync
2+
3+
import io.swagger.v3.oas.annotations.media.Schema
4+
import java.time.LocalDateTime
5+
6+
@Schema(description = "Request to update an organisation's address-specific phone number")
7+
data class SyncUpdateAddressPhoneRequest(
8+
@Schema(description = "Type of phone", example = "MOB")
9+
val phoneType: String,
10+
11+
@Schema(description = "Phone number", example = "+1234567890")
12+
val phoneNumber: String,
13+
14+
@Schema(description = "Extension number", example = "123")
15+
val extNumber: String? = null,
16+
17+
@Schema(description = "The username of the person who made the update", example = "JD000001")
18+
val updatedBy: String,
19+
20+
@Schema(description = "The time when the update was made", example = "2024-01-01T00:00:00Z")
21+
val updatedTime: LocalDateTime,
22+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package uk.gov.justice.digital.hmpps.organisationsapi.model.response.sync
2+
3+
import io.swagger.v3.oas.annotations.media.Schema
4+
import java.time.LocalDateTime
5+
6+
@Schema(description = "An organisation's address-specific phone number")
7+
data class SyncAddressPhoneResponse(
8+
@Schema(description = "Unique identifier for the address-specific phone number", example = "1")
9+
val organisationAddressPhoneId: Long,
10+
11+
@Schema(description = "Unique identifier for the address to which this phone number is linked", example = "1")
12+
val organisationAddressId: Long,
13+
14+
@Schema(description = "Unique identifier for the phone record", example = "1")
15+
val organisationPhoneId: Long,
16+
17+
@Schema(description = "Unique identifier for the organisation linked to this address", example = "1")
18+
val organisationId: Long,
19+
20+
@Schema(description = "Type of phone", example = "MOB")
21+
val phoneType: String,
22+
23+
@Schema(description = "Phone number", example = "+1234567890")
24+
val phoneNumber: String,
25+
26+
@Schema(description = "Extension number", example = "123")
27+
val extNumber: String?,
28+
29+
@Schema(description = "User who created the entry", example = "admin")
30+
val createdBy: String,
31+
32+
@Schema(description = "Timestamp when the entry was created", example = "2023-09-23T10:15:30")
33+
val createdTime: LocalDateTime,
34+
35+
@Schema(description = "User who updated the entry", example = "admin2")
36+
val updatedBy: String? = null,
37+
38+
@Schema(description = "Timestamp when the entry was updated", example = "2023-09-24T12:00:00")
39+
val updatedTime: LocalDateTime? = null,
40+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
package uk.gov.justice.digital.hmpps.organisationsapi.resource.sync
2+
3+
import io.swagger.v3.oas.annotations.Operation
4+
import io.swagger.v3.oas.annotations.Parameter
5+
import io.swagger.v3.oas.annotations.media.Content
6+
import io.swagger.v3.oas.annotations.media.Schema
7+
import io.swagger.v3.oas.annotations.responses.ApiResponse
8+
import io.swagger.v3.oas.annotations.responses.ApiResponses
9+
import io.swagger.v3.oas.annotations.security.SecurityRequirement
10+
import io.swagger.v3.oas.annotations.tags.Tag
11+
import jakarta.validation.Valid
12+
import org.springframework.http.MediaType
13+
import org.springframework.security.access.prepost.PreAuthorize
14+
import org.springframework.web.bind.annotation.DeleteMapping
15+
import org.springframework.web.bind.annotation.GetMapping
16+
import org.springframework.web.bind.annotation.PathVariable
17+
import org.springframework.web.bind.annotation.PostMapping
18+
import org.springframework.web.bind.annotation.PutMapping
19+
import org.springframework.web.bind.annotation.RequestBody
20+
import org.springframework.web.bind.annotation.RequestMapping
21+
import org.springframework.web.bind.annotation.ResponseBody
22+
import org.springframework.web.bind.annotation.RestController
23+
import uk.gov.justice.digital.hmpps.organisationsapi.facade.SyncFacade
24+
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncCreateAddressPhoneRequest
25+
import uk.gov.justice.digital.hmpps.organisationsapi.model.request.sync.SyncUpdateAddressPhoneRequest
26+
import uk.gov.justice.digital.hmpps.organisationsapi.model.response.sync.SyncAddressPhoneResponse
27+
import uk.gov.justice.digital.hmpps.organisationsapi.swagger.AuthApiResponses
28+
import uk.gov.justice.hmpps.kotlin.common.ErrorResponse
29+
30+
@Tag(name = "Migration and synchronisation")
31+
@RestController
32+
@RequestMapping(value = ["sync"], produces = [MediaType.APPLICATION_JSON_VALUE])
33+
@AuthApiResponses
34+
class SyncAddressPhoneController(val syncFacade: SyncFacade) {
35+
36+
@GetMapping(path = ["/organisation-address-phone/{organisationAddressPhoneId}"], produces = [MediaType.APPLICATION_JSON_VALUE])
37+
@Operation(
38+
summary = "Returns the data for one organisation address phone number by ID",
39+
description = """
40+
Requires role: ROLE_ORGANISATIONS_MIGRATION.
41+
Used to get the details for one organisation address phone number by ID.
42+
""",
43+
security = [SecurityRequirement(name = "bearer")],
44+
)
45+
@ApiResponses(
46+
value = [
47+
ApiResponse(
48+
responseCode = "200",
49+
description = "Returning the details of the organisation address-linked phone number",
50+
content = [
51+
Content(
52+
mediaType = "application/json",
53+
schema = Schema(implementation = SyncAddressPhoneResponse::class),
54+
),
55+
],
56+
),
57+
ApiResponse(
58+
responseCode = "400",
59+
description = "The request has invalid or missing fields",
60+
content = [Content(schema = Schema(implementation = ErrorResponse::class))],
61+
),
62+
ApiResponse(
63+
responseCode = "404",
64+
description = "No organisation address number with the requested ID was found",
65+
content = [Content(schema = Schema(implementation = ErrorResponse::class))],
66+
),
67+
],
68+
)
69+
@PreAuthorize("hasAnyRole('ROLE_ORGANISATIONS_MIGRATION')")
70+
fun syncGetAddressPhoneById(
71+
@Parameter(description = "The internal ID for an organisation address-linked phone number", required = true)
72+
@PathVariable organisationAddressPhoneId: Long,
73+
) = syncFacade.getAddressPhoneById(organisationAddressPhoneId)
74+
75+
@DeleteMapping(path = ["/organisation-address-phone/{organisationAddressPhoneId}"], produces = [MediaType.APPLICATION_JSON_VALUE])
76+
@Operation(
77+
summary = "Deletes one organisation address-linked phone number by internal ID",
78+
description = """
79+
Requires role: ROLE_ORGANISATIONS_MIGRATION.
80+
Used to delete an organisation's address-linked phone number by internal ID.
81+
""",
82+
security = [SecurityRequirement(name = "bearer")],
83+
)
84+
@ApiResponses(
85+
value = [
86+
ApiResponse(
87+
responseCode = "204",
88+
description = "Successfully deleted the organisation address phone number",
89+
),
90+
ApiResponse(
91+
responseCode = "404",
92+
description = "No organisation address-linked phone number with the requested ID was found",
93+
content = [Content(schema = Schema(implementation = ErrorResponse::class))],
94+
),
95+
],
96+
)
97+
@PreAuthorize("hasAnyRole('ROLE_ORGANISATIONS_MIGRATION')")
98+
fun syncDeleteAddressPhoneById(
99+
@Parameter(description = "The internal ID for the organisation address-linked phone number.", required = true)
100+
@PathVariable organisationAddressPhoneId: Long,
101+
) = syncFacade.deleteAddressPhone(organisationAddressPhoneId)
102+
103+
@PostMapping(path = ["/organisation-address-phone"], produces = [MediaType.APPLICATION_JSON_VALUE])
104+
@ResponseBody
105+
@Operation(
106+
summary = "Creates a new address-linked phone number for an organisation",
107+
description = """
108+
Requires role: ROLE_ORGANISATIONS_MIGRATION.
109+
Used to create a new address-linked phone number for an organisation.
110+
""",
111+
security = [SecurityRequirement(name = "bearer")],
112+
)
113+
@ApiResponses(
114+
value = [
115+
ApiResponse(
116+
responseCode = "201",
117+
description = "Successfully created the address-linked phone number for an organisation",
118+
content = [
119+
Content(
120+
mediaType = "application/json",
121+
schema = Schema(implementation = SyncAddressPhoneResponse::class),
122+
),
123+
],
124+
),
125+
ApiResponse(
126+
responseCode = "400",
127+
description = "The request has invalid or missing fields",
128+
content = [Content(schema = Schema(implementation = ErrorResponse::class))],
129+
),
130+
ApiResponse(
131+
responseCode = "404",
132+
description = "The organisation or address was not found",
133+
content = [Content(schema = Schema(implementation = ErrorResponse::class))],
134+
),
135+
],
136+
)
137+
@PreAuthorize("hasAnyRole('ROLE_ORGANISATIONS_MIGRATION')")
138+
fun syncCreateAddressPhone(
139+
@Valid @RequestBody syncCreateAddressPhoneRequest: SyncCreateAddressPhoneRequest,
140+
) = syncFacade.createAddressPhone(syncCreateAddressPhoneRequest)
141+
142+
@PutMapping(path = ["/organisation-address-phone/{organisationAddressPhoneId}"], produces = [MediaType.APPLICATION_JSON_VALUE])
143+
@ResponseBody
144+
@Operation(
145+
summary = "Updates an organisation address-linked phone number with altered or additional details",
146+
description = """
147+
Requires role: ROLE_ORGANISATIONS_MIGRATION.
148+
Used to update an organisation's address-linked phone number.
149+
""",
150+
security = [SecurityRequirement(name = "bearer")],
151+
)
152+
@ApiResponses(
153+
value = [
154+
ApiResponse(
155+
responseCode = "200",
156+
description = "Successfully updated the organisation's address-linked phone number",
157+
content = [
158+
Content(
159+
mediaType = "application/json",
160+
schema = Schema(implementation = SyncAddressPhoneResponse::class),
161+
),
162+
],
163+
),
164+
ApiResponse(
165+
responseCode = "404",
166+
description = "The organisation, address or phone number was not found",
167+
content = [Content(schema = Schema(implementation = ErrorResponse::class))],
168+
),
169+
ApiResponse(
170+
responseCode = "400",
171+
description = "Invalid request data",
172+
content = [Content(schema = Schema(implementation = ErrorResponse::class))],
173+
),
174+
],
175+
)
176+
@PreAuthorize("hasAnyRole('ROLE_ORGANISATIONS_MIGRATION')")
177+
fun syncUpdateAddressPhone(
178+
@Parameter(description = "The internal ID for the organisation address-linked phone number.", required = true)
179+
@PathVariable organisationAddressPhoneId: Long,
180+
@Valid @RequestBody syncUpdateAddressPhoneRequest: SyncUpdateAddressPhoneRequest,
181+
) = syncFacade.updateAddressPhone(organisationAddressPhoneId, syncUpdateAddressPhoneRequest)
182+
}

0 commit comments

Comments
 (0)